--llog_test_llog_init --llog_setup --llog_new_ctxt --llog_operations::lop_setup --llog_run_tests
--llog_get_context
--llog_test_1: test named-log create/open,close --llog_get_context --llog_create(ctxt, &llh, NULL, name): --llog_obd2ops(ctxt, &lop): get the correponding llog_operation from give ctxt --lop->lop_create --llog_lvfs_create: --llog_alloc_handle --如果指定了logid或者name,则根据logid或者name获取handle->lgh_file,否 则执行如下: --OBDO_ALLOC(oa): 分配obdo结构 --obd_create(ctxt->loc_exp, oa, NULL, NULL):对应于llog_test中为空 --obd_lvfs_fid2dentry: 获取由oa决定的logid对应的dentry结构 --l_dentry_open: 获取handle->lgh_file --llog_init_handle(llh, LLOG_F_IS_PLAIN, &uuid) --llog_read_header: 对应于llog_lvfs_ops::llog_lvfs_read_header --llog_lvfs_read_blob: --fsfilt_read_record --fsfilt_ext3_read_record: 该函数很简单 --rc2 = llog_close(llh)
--llog_test_2: test named-log reopen,returns opened log on success --llog_get_context --llog_create: re-open a log with name,前面已经讲解。 --llog_init_handle --后面的操作都是和这里类似,重复测试handle创建销毁操作 --llog_test_3: test record writing,single and in bulk --llog_write_rec: write one create_rec --llog_write_rec: write 10 cfg log records with 8 bytes bufs --llog_write_rec: write 1000 more log records --llog_write_rec(struct llog_handle *handle,
struct llog_rec_hdr *rec,
struct llog_cookie *logcookies,
int numcookies, void *buf, int idx): --llog_handle2ops(handle, &lop) --lop->lop_write_rec(handle, rec, logcookies, numcookies, buf, idx) --llog_lvfs_write_rec如果指定idx不为-1,则表示修改record @idx,否则表示我 们添加日志记录,但是令我疑惑的是为什么无论idx是否为-1,都会事先调用
llog_lvfs_write_blob(obd, file, &llh->llh_hdr, NULL, 0)来写llh->llh_hdr,这不仅仅是更新啊,因为每次写的时候file- >pos变了啊。。。取而代之每次写都是将llh->llh_hdr写到文件中file->pos位置?????? --llog_lvfs_write_blob --int buflen = rec->lrh_len;除llog_log_hdr外,其他的任何llog_**_rec中的 llog_rec_hdr中的lrh_len都表示该记录的长度,如果buf为空则直接调用 fsfilt_write_record,否则调用fsfilt_write_record三次,分 别写 llog_rec_hdr,buf和llog_rec_tail. --fsfilt_write_record的原型为:fsfilt_write_record(struct obd_device *obd, struct file *file,void *buf, loff_t size, loff_t *offs,int force_sync) --fsfilt_ext3_write_record:在这里就和ext3的底层日志相结合了,使用了 ext3_journal_start等。
--llog_test_4: Test catalogue additions --llog_create(ctxt, &cath, NULL, name) --llog_init_handle(cath, LLOG_F_IS_CAT, &uuid): 初始化日志句柄为catalogue --llog_cat_add_rec(cath, &lmr.lmr_hdr, &cookie, NULL): write 1 record into the catalog,返 回的cookie用于后面
的llog_cat_cancel_records --llog_cat_current_log: return the currently active log handle, If the current log handle doesn't have enouth space left for the current record,then start a new one --loghandle = cathandle->u.chd.chd_current_log;获取当前llog_handle --如果loghandle->lgh_last_idx < LLOG_BITMAP_SIZE(llh) - 1 则直接返回该 loghandle --否则根据参数传递的create标志决定是否通过llog_cat_new_log创建新的 llog_handle。llog_cat_new_log如下: --llog_create: 创建llog_handle --llog_init_handle: 初始化新创建的llog_handle --ext2_set_bit: 设置某个index被占用 --llog_write_rec: update the catalog: header and record,此时写的record是 llog_logid_rec类型,表示plain log 在catalog中的id --list_add_tail(&loghandle->u.phd.phd_entry, &cathandle->u.chd.chd_head);将新建 的llog_handle加入到catalog对应的链表中。 --llog_write_rec --llog_cat_cancel_records(cath, 1, &cookie): cancel 1 log record,for each cookie in the cookie array, we clear the log in-use bit and either: * the log is empty,so mark it free in the catalog header and delete it * the log is not empty,just write out the log header 对cookies数组中的每一个cookie执行: --struct llog_logid *lgl = &cookies->lgc_lgl --llog_cat_id2handle(cathandle,&loghandle,lgl) --list_for_each_entry(loghandle, &cathandle->u.chd.chd_head,
u.phd.phd_entry)遍历cathandle->u.chd.chd_head链表查找 --这里在没有查找到的情况下又会创建一个llog_handle,并添加到cathandle链表
中,这有必要么??? --llog_cancel_rec(loghandle, cookies->lgc_index) --ext2_clear_bit --llog_write_rec(loghandle, &llh->llh_hdr, NULL, 0, NULL, 0) update the header and record --如果该llog_handle只剩下头记录(llog_log_hdr),则调用llog_destroy --llog_test_5:Test log and catalogue processing,主要测 llog_cat_process,llog_cat_reverse_process,llog_process --llog_process: --根据参数初始化结构体struct llog_process_info *lpi --llog_process_thread(lpi) --忽略bitmap中没有设置的record --llog_next_block(loghandle, &saved_index, index,
&cur_offset, buf, LLOG_CHUNK_SIZE); --llog_lvfs_next_block(struct llog_handle *loghandle, int *cur_idx, int next_idx, __u64 *cur_offset, void *buf, int len):其中cur_offset:to the furthest point in the log file cur_idx: to the log index preceeding cur_offset, len: 读的长度 费解这里为什么给的cur_offset是从LLOG_CHUNK_SIZE开始的????? --llog_skip_over(cur_offset, *cur_idx, next_idx):跳过cur_idx到next_idx之间的记 录??根据注释“We can skip reading at least as many log blocks as the number of minimum sized log records we are skipping” 我们知道这里实际上是一种优化而已,并 不一定忽略了所有cur_idx到next_idx之间的记录,会更新cur_offset --fsfilt_read_record --fsfilt_ext3_read_record --tail = (struct llog_rec_tail *)((char *)buf + rc -
sizeof(struct llog_rec_tail));获取 llog_rec_tail --*cur_idx = tail->lrt_index;更新cur_idx --if (tail->lrt_index < next_idx)
continue; 如果还没有到next_idx则继续 --对刚才读出的buf中的每一个记录进行处理: for (rec = (struct llog_rec_hdr *)buf;
(char *)rec < buf + LLOG_CHUNK_SIZE;
rec = (struct llog_rec_hdr *)((char *)rec + rec->lrh_len)) 调用lpi->lpi_cb(loghandle, rec,lpi->lpi_cbdata) --llog_cat_process:该函数仍然调用llog_process处理,传递的回调函数为 llog_cat_process_cb,如下: --llog_cat_process_cb(struct llog_handle *cat_llh, struct llog_rec_hdr *rec,
void *data):该函数用于处理catlogue中的每个关于plain log的 记录,因为每个记录都对应于一个 llog_handle,所以最后还是要调用llog_process来处理每个plain log
--llog_cat_id2handle(cat_llh, &llh, &lir->lid_id): 通过llog_logid_rec获取catlogue 中对应的llog_handle --llog_process(llh, d->lpd_cb, d->lpd_data, NULL):处理返回的llog_handle --llog_cat_reverse_process:llog_cat_reverse_process和llog_cat_process类似,只不过是调 用的函数是 llog_reverse_process,在此不表
--llog_test_6: Test client api; open log by name and process,但是这里到底是为了测试 什么,没有看懂?????
obd_setup调用关系1:
ll_fill_super(struct super_block *sb):这里是CLIENT端的
--lustre_process_log(struct super_block *sb, char *logname, struct config_llog_instance *cfg)
--mgc_process_config(struct obd_device *obd, obd_count len, void *buf)
--class_config_parse_llog(struct llog_ctxt *ctxt, char *name,
struct config_llog_instance *cfg) --class_config_llog_handler(struct llog_handle * handle,
struct llog_rec_hdr *rec, void *data) --class_process_config(struct lustre_cfg *lcfg) --class_setup(struct obd_device *obd, struct lustre_cfg *lcfg) --obd_setup(struct obd_device *obd, int datalen, void *data)
obd_setup调用关系2:
server_start_targets(struct super_block *sb, struct vfsmount *mnt):这里启动的可能是MDS或者OSD
--lustre_start_simple(char *obdname, char *type, char *uuid, char *s1, char *s2) --do_lcfg(char *cfgname, lnet_nid_t nid, int cmd, char *s1, char *s2, char *s3, char *s4) --class_process_config(struct lustre_cfg *lcfg)
--class_setup(struct obd_device *obd, struct lustre_cfg *lcfg) --obd_setup(struct obd_device *obd, int datalen, void *data)
lustre_start_simple(char *obdname, char *type, char *uuid, char *s1, char *s2) --do_lcfg(obdname, 0, LCFG_ATTACH, type, uuid, 0, 0) --do_lcfg(obdname, 0, LCFG_SETUP, s1, s2, 0, 0) --初始化struct lustre_cfg_bufs bufs;
--struct lustre_cfg * lcfg = lustre_cfg_new(cmd, &bufs):根据cmd和bufs生成lcfg --class_process_config(lcfg):处理lcfg
--obd = class_name2obd(lustre_cfg_string(lcfg, 0)):据name获取obd,这里的name就 是lustre_start_simple中的obdname
--当lcfg->lcfg_command是LCFG_SETUP时,调用class_setup。 --obd_setup(struct obd_device *obd, int datalen, void *data):将调用obd对应的 obd_type->typ_ops->o_setup,相应的有mds_obd_ops,mdt_obd_ops,fileter_obd_ops, ost_obd_ops,llog_obd_ops等。但是我们必须搞清楚 server_start_targets-->lustre_start_simple调用路径上到底会调用哪些***_obd_ops对setup 函数。根据 server_start_targets实现可知,该函数是启动target,也就是OST,MDT等。 所以我们可以server_start_targets->lustre_start_simple调用路径上是如果没有启动MDS 或者OSS则启动之,所以会调用mds_obd_ops或者ost_obd_ops对应的setup(注意这 里根据lustre代码中的注释,LUSTRE_OSS_NAME它搞成ost了,而 LUSTRE_OST_NAME它搞成obdfilter了,而且注释中说了LUSTRE_OSS_NAME应该 为oss,LUSTRE_OST_NAME应该为ost,所以filter_obd_ops实际上应该为ost_obd_ops, ost_obd_ops实际上应该为oss_obd_ops),今天暂时分析到此,明天继续分析这些setup 与哪些llog_ctxt相关???另外这 些targets的启动是通过 server_start_targets--->lustre_process_log(sb, lsi->lsi_ldd->ldd_svname, &cfg)启动的,这个 也要分析。。。还有llog_test是如何被启动的。。。明天待续。。。。
关于MDS/OSS的建立
lustre_start_simple--->......--->obd_setup路径,对应于MDS是mds_obd_ops中的mds_setup(但是从lustre的debug信息来看,是mdt_setup,这里mdt_setup的实现和ost_setup类似,都是调用ptlrpc_init_svc初始化多个服务,并对不同的服务调用ptlrpc_start_threads启动,而在ptlrpc_init_svc中传递的处理函数则为mds_handle,所以说对于mds和mdt,lustre的设计人员再次弄反了),对应于OSS则是ost_obd_ops中的ost_setup,下面我们看mdt_setup和ost_setup:
ost_setup:该函数中三次调用ptlrpc_init_svc和ptlrpc_start_threads分别启动ost_service,ost_create_service,ost_io_service,最后调用ping_evictor_start启动ping evictor --ost->ost_service =ptlrpc_init_svc(...,ost_handle,...)
--OBD_ALLOC(service, sizeof(*service)):分配service结构
--初始化service,其中重要的是初始化struct ptlrpc_at_array *array = &service->srv_at_array;该array中存放reqs waiting for replies,这里的at代表adaptive timeout。
--size = at_est2timeout(at_max):根据at_max估算出size
--OBD_ALLOC(array->paa_reqs_array, sizeof(struct list_head) * size):paa_reqs_array是用 来存放request的
--cfs_timer_init(&service->srv_at_timer, ptlrpc_at_timer, service):这里初始化定时器,回 调函数为ptlrpc_at_timer,service将作为回调函数的参数
--at_init(&service->srv_at_estimate, 10, 0):初始化adaptive_timeout参数
--ptlrpc_grow_req_bufs(service):分配request buffers,实际上分配ptlrpc_service :: srv_nbuf_per_group个ptlrpc_request_buffer_desc结构(调用ptlrpc_alloc_rqbd),并将之 连接到 ptlrpc_service::srv_idle_rqbds链表中。在ptlrpc_alloc_rqbd中又调用 ptlrpc_alloc_request_buffer分配ptlrpc_request_buffer_desc::rqbd_buffer。从这里我们可以 看出对于每个ptlrpc_service结构有ptlrpc_service :: srv_nbuf_per_group个request buffer,每个request buffer对应一个ptlrpc_request_buffer_desc,也就是说这个
ptlrpc_request_buffer_desc就是用于描述这个request buffer的,真正的buffer内容则放在ptlrpc_request_buffer_desc::rqbd_buffer中。 --设置ptlrpc_service::srv)max_reply_size
另外,在用ptlrpc_init_svc初始化ost->ost_io_service之后,还将对ost->ost_io_svc作如 下:
ost->ost_io_service->srv_init = ost_thread_init;用于初始化每个线程的状态 ost->ost_io_service->srv_done = ost_thread_done;用于销毁srv_init中的状态 ost->ost_io_service->srv_cpu_affinity = 1; --ptlrpc_start_threads(obd, ost->ost_service)
--调用ptlrpc_start_thread启动ptlrpc_service::srv_threads_min个线程,ptlrpc_start_thread 原型:ptlrpc_start_thread(struct obd_device *dev, struct ptlrpc_service *svc)
--OBD_ALLOC(thread, sizeof(*thread)) --cfs_waitq_init(&thread->t_ctl_waitq)
--list_add(&thread->t_link, &svc->srv_threads) --id = svc->srv_threads_started++
--thread->t_svc = svc; thread->t_id = id;
--struct ptlrpc_svc_data d ;d.dev = dev;d.svc = svc;d.name = name;d.thread = thread; --cfs_kernel_thread(ptlrpc_main, &d, CLONE_VM | CLONE_FILES)ptlrpc_main原型: ptlrpc_main(void *arg)
--根据参数arg初始化变量
struct ptlrpc_svc_data *data = (struct ptlrpc_svc_data *)arg; struct ptlrpc_service *svc = data->svc;
struct ptlrpc_thread *thread = data->thread; struct obd_device *dev = data->dev; struct ptlrpc_reply_state *rs; --ptlrpc_daemonize(data->name)
--如果定义了ptlrpc_service::srv_init则调用之 if (svc->srv_init != NULL) rc = svc->srv_init(thread);
--OBD_ALLOC_GFP(rs, svc->srv_max_reply_size, CFS_ALLOC_STD): 分配reply state structure,从这里我们可以看出每一个线程都对应一个replay_state,因为每一 个线程一次处理一个请求?????
--标记线程为运行状态并唤醒线程等待队列中等待的进程:
thread->t_flags = SVC_RUNNING;
cfs_waitq_signal(&thread->t_ctl_waitq);在ptlrpc_start_thread中进入等待
--将该reply_state结构加入service的free reply state链表,并唤醒等待reply_state 结构的线程
list_add(&rs->rs_list, &svc->srv_free_rs_list) cfs_waitq_signal(&svc->srv_free_rs_waitq);
--进入循环处理请求,循环条件为(thread->t_flags & SVC_STOPPING) == 0 ||
svc->srv_n_difficult_replies != 0),前者表示线程仍然在运行,后者表示线程还有未 处理完的请求。
--l_wait_event_exclusive(svc->srv_waitq,condition,&lwi)等待事件发生
--ptlrpc_check_rqbd_pool(svc)
--检查线程数目,如果满足((svc->srv_threads_started < svc->srv_threads_max) &&
(svc->srv_n_active_reqs >= (svc->srv_threads_started - 1)))则 启动新的线程
--如果svc->srv_reply_queue不空,则调用ptlrpc_server_handle_reply(svc),关于 ptlrpc_server_handle_reply的讲解见下面
--如果svc->srv_req_in_queue不空则调用ptlrpc_server_handle_req_in(svc),关于 ptlrpc_server_handle_req_in的讲解见下面
--如果指定了svc->srv_at_check则调用ptlrpc_at_check_timed(svc),关于 ptlrpc_at_check_timed的讲解见下面
--如果满足svc->srv_request_queue不为空且svc->srv_n_active_reqs < (svc->srv_threads_running - 1)则调用 ptlrpc_server_handle_request(svc,thread),注意 这里我们省略了ptlrpc_server_request_pending--->ptlrpc_server_allow_normal逻辑, 因为我们暂时不关心这个。关于ptlrpc_server_handle_request讲解见下面。 --如果svc->srv_idle_rqbds不为空则执行ptlrpc_server_post_idle_rqbds,关于 ptlrpc_server_post_idle_rqbds讲解见下面。我们需要搞清楚idle_rebds和active_rqbds 都是用于什么的?Rqbd如何在这两个链表之间转换,request又是如何和rqbd关联 的?见后面会讲解的。。。。
--l_wait_event(thread->t_ctl_waitq,
thread->t_flags & (SVC_RUNNING | SVC_STOPPED), &lwi) --ping_evictor_start()
ptlrpc_server_handle_reply (struct ptlrpc_service *svc) --如果list_empty(&svc->srv_reply_queue)则返回 --否则struct ptlrpc_reply_state *rs;
rs = list_entry (svc->srv_reply_queue.next,
struct ptlrpc_reply_state, rs_list);关于ptlrpc_reply_state,其最后一个域为struct lustre_msg结构,这里才是存放真正的响应信息。还有一个ptlrpc_reply_state::rs_export,从target_send_reply实现来看,这个rs_export是直接和ptlrpc_request::rq_export相同,那么ptlrpc_request::rq_export是什么呢????关于ptlrpc_request中的import和export及ptlrpc_reply_state中的export都不知道是什么?? --从三个链表中删除该ptlrpc_reply_state,但是为什么要用这么多的链表来维护呢?
list_del_init (&rs->rs_list); list_del_init (&rs->rs_obd_list); list_del_init (&rs->rs_exp_list); --记录之前是否被处理,并设置为处理状态。 been_handled = rs->rs_handled; rs->rs_handled = 1;
--接下来的代码就有点看不懂了???这里哪里有handle的代码啊????
ptlrpc_server_handle_req_in(struct ptlrpc_service *svc):handle freshly incoming reqs, add to timed early reply list,pass on to regular request queue
--如果if (list_empty(&svc->srv_req_in_queue)) 则直接返回
--从srv_req_in_queue获取一个请求:
req = list_entry(svc->srv_req_in_queue.next,
struct ptlrpc_request, rq_list); --list_del_init (&req->rq_list)
--lustre_unpack_msg(req->rq_reqmsg, req->rq_reqlen),获取req->rq_reqmsg --初始化req->rq_export????
req->rq_export = class_conn2export(
lustre_msg_get_handle(req->rq_reqmsg));关于这个req->rq_export 的赋值多说一点:首先通过lustre_msg_get_handle获取对应的lustre_handle结构,然后 调用class_conn2export,调用关系为class_conn2export(struct lustre_handle *conn)--->class_handle2object(__u64 cookie),在class_handle2object中我们看到了一个全 局的handle_hash变量,该变量是在定义handle_bucket的时候顺便定义的,如下:
static struct handle_bucket { spinlock_t lock;
struct list_head head; } *handle_hash;
我们知道handle_bucket表示hash表中的一个桶,而struct handle_bucket* 可以表示一 个handle_bucket数组,所以这里handle_hash实际上就是一个数组。然后 class_handle2object的处理就很简单了,先通过cookie找到对应的桶:
bucket = handle_hash + (cookie & HANDLE_HASH_MASK);
然后遍历这个桶找到对应的portals_handle。Struct lustre_handle,struct portals_handle, struct obd_export定义如下,可以看到这三者之间的关联。
struct obd_export {
struct portals_handle exp_handle;
。。。。。。
}
struct portals_handle {
struct list_head h_link; __u64 h_cookie;
portals_handle_addref_cb h_addref;
/* newly added fields to handle the RCU issue. -jxiong */ spinlock_t h_lock; void *h_ptr;
void (*h_free_cb)(void *, size_t); struct rcu_head h_rcu; unsigned int h_size; __u8 h_in:1;
__u8 h_unused[3]; };
struct lustre_handle { __u64 cookie;
};
那么我们也肯能会问何时我们加入struct portals_handle到hash表中的呢?如果我们只关注export的话,那就是在class_new_export--->class_handle_hash中,当然在其他某些函数中也会调用class_handle_hash加入到hash表中。那么portals_handle中的这个cookie值是何时产生的呢,答案是在class_handle_hash:Generate a unique 64bit cookie (hash) for a handle and insert it into global (per-node) hash-table,在class_handle_hash中我们会对全局变量handle_base做如下:handle_base += HANDLE_INCR;并且使portals_handle::h_cookie = handle_base,然后以此portals_handle::h_cookie 为key进行hash,查找对应的bucket并插入。注意在class_handle_hash,原型为: class_handle_hash(struct portals_handle *h, portals_handle_addref_cb cb),也就是说这个产生的cookie会通过参数被返回的。那么这些request又是如何和lustre_handle关联上的呢?只有在lustre_msg_set_handle中会给request中相应的lustre_handle赋值。但是调用lustre_msg_set_handle的函数中我不能确定是否就是这么给request中lustre_handle赋值的?????
--对request进行必要的检查ptlrpc_check_req,是否是旧的链接的request?是否request对应的 req->rq_export->exp_obd->obd_fail,如果是则出错返回,否则继续。
if (req->rq_export) {
rc = ptlrpc_check_req(req); if (rc)
goto err_req;
ptlrpc_update_export_timer(req->rq_export, 0); }
--设置ptlrpc_request对应的rq_deadline
--ptlrpc_at_add_timed(req): add req to early reply check list --确认list_empty(&req->rq_timed_list)成立
--获取该ptlrpc_request应该在ptlrpc_service::ptlrpc_at_array中应该存放的位置
index = (unsigned long)req->rq_deadline % array->paa_size;
--在array->paa_reqs_array[index]链表中寻找一个合适的位置插入该ptlrpc_request -- 如果没有找到合适的位置插入,则插入到链表头部
if (list_empty(&req->rq_timed_list))
list_add(&req->rq_timed_list, &array->paa_reqs_array[index]);
-- 设置array->paa_deadline:
if (array->paa_count == 1 || array->paa_deadline > req->rq_deadline) { array->paa_deadline = req->rq_deadline; found = 1; }
-- 如果found在上述判断中置1则调用ptlrpc_at_set_timer,为最近的deadline设置 定时器。
if (found)
ptlrpc_at_set_timer(svc);
--ptlrpc_hpreq_init(svc, req):这里是对高优先级的请求的处理(暂时不用care)。如果定义了svc->srv_hpreq_handler,则直接调用 svc->srv_hpreq_handler处理该请求,否则如果request本身指定了high-priority request handler则添加到server端的per-export的待处理rpc请 求队列,list_add(&req->rq_exp_list , &req->rq_export->exp_queued_rpc)。 这
里我们暂时不关心优先级的问题。 --ptlrpc_server_request_add(svc, req)
--ptlrpc_server_hpreq_check(req): 检查该req是否是一个high priority request,是则 返回1,否则返回0,错误返回<0
--如果满足if (req->rq_phase == RQ_PHASE_NEW && list_empty(&req->rq_list)):
如果rc=1,则调用ptlrpc_hpreq_reorder_nolock使之成为一个high priority request 如果rc=0,则list_add_tail(&req->rq_list, &svc->srv_request_queue)
--cfs_waitq_signal(&svc->srv_waitq):当有新的请求到来或者difficult reply要处理的时候被唤醒
--如果出错则调用ptlrpc_server_finish_request(req)
ptlrpc_at_check_timed(struct ptlrpc_service *svc):Send early replies to everybody expiring within at_early_margin asking for at_extra time --获取当前时间并计算svc->srv_at_array->paa_deadline距离now的时间间隔,如果时间间 隔大于@at_early_margin,则重置定时器。
time_t now = cfs_time_current_sec(); Int first = array->paa_deadline - now;
if (first > at_early_margin) {
/* We've still got plenty of time. Reset the timer. */ spin_unlock(&svc->srv_at_lock); ptlrpc_at_set_timer(svc); RETURN(0); }
在ptlrpc_at_set_timer中,首先计算最近的到期时间与当前时间以及at_early_margin的 差值next,如果next<=0则表示时间到,直接调用ptlrpc_at_timer唤醒悬挂在 svc->srv_waitq上的线程来处理请求;否则重新设置定时器。代码如下:
next = (__s32)(array->paa_deadline - cfs_time_current_sec() - at_early_margin); if (next <= 0)
ptlrpc_at_timer((unsigned long)svc); else
cfs_timer_arm(&svc->srv_at_timer, cfs_time_shift(next));
--否则first<=at_early_margin,则请求即将超时,但是我们不知道server会花多长时间来处 理,所以先发送early replies给所有即将超时的请求,代码如下:
CFS_INIT_LIST_HEAD(&work_list);初始化工作队列
index = (unsigned long)array->paa_deadline % array->paa_size;超时请求所在链表索引 count = array->paa_count;在ptlrpc_service::srv_at_array中的请求总数 while (count > 0) {
count -= array->paa_reqs_count[index];
list_for_each_entry_safe(rq, n, &array->paa_reqs_array[index], rq_timed_list) {
if (rq->rq_deadline <= now + at_early_margin) {
//添加到待处理链表
list_move(&rq->rq_timed_list, &work_list); counter++;
array->paa_reqs_count[index]--; array->paa_count--; rq->rq_at_linked = 0; continue; }
/* 用这些还未在超时窗口内的请求的deadline更新deadline变 量,该变量最终会赋值给array->paa_deadline */ if (deadline == -1 || rq->rq_deadline < deadline) deadline = rq->rq_deadline;
break; }
if (++index >= array->paa_size)//处理其他index的链表中的请求 index = 0;//wrap around }
array->paa_deadline = deadline;//更新array的最后期限
--因为上面我们更新了array->paa_deadline,所以调用ptlrpc_at_set_timer(svc);重新启动定 时器,该函数在前面讲过,在此不表
--处理处于work_list中的请求,从work_list中删除,并调用ptlrpc_at_send_early_reply和 ptlrpc_server_drop_request,代码如下: while (!list_empty(&work_list)) {
rq = list_entry(work_list.next, struct ptlrpc_request,rq_timed_list); list_del_init(&rq->rq_timed_list);//删除之 atomic_inc(&rq->rq_refcount); spin_unlock(&svc->srv_at_lock);
if (ptlrpc_at_send_early_reply(rq, at_extra) == 0)//成功返回0,见下面讲解 ptlrpc_at_add_timed(rq);//Add rpc to early reply check list,这里为什么要再次加入到ptlrpc_service::srv_at_array中呢,因为从ptlrpc_server_handle_req_in函数我们知道对于所有的request,我们都是先加入到ptlrpc_service::srv_at_array中,接着又会加入到ptlrpc_service::srv_request_queue中去等待处理,然后在ptlrpc_server_handle_request中会去处理ptlrpc_service::srv_request_queue(其调用关系为ptlrpc_start_thread--->ptlrpc_main--->ptlrpc_server_handle_request---> ptlrpc_server_request_get ---> 从ptlrpc_service:: srv_request_queue中 获取请求来处理)中的请求,同时ptlrpc_at_check_timed(其调用关系为ptlrpc_start_thread---> ptlrpc_main---> ptlrpc_at_check_timed)也会去处理ptlrpc_service::srv_at_array中的请求,对于其中的请求如果ptlrpc_request::rq_sent_final则表示该请求已经处理过了(应该就是在ptlrpc_service:: srv_request_queue中被处理的),所以直接略过该请求(这在下面的ptlrpc_at_send_early_reply中会有讲解)。
ptlrpc_server_drop_request(rq);/*drop a reference count of the request. if it reaches 0, we either put it into history list, or free it immediately.这 里我们不用担心没被处理就释放了,因为有引用计数呢见后面讲解*/ spin_lock(&svc->srv_at_lock); }
ptlrpc_at_send_early_reply(struct ptlrpc_request *req,int extra_time) --计算oldd1,long olddl = req->rq_deadline - cfs_time_current_sec();
--如果olddl < 0 则提示超时,考虑修改at_early_margin,返回-ETIMEDOUT --设置newdl值,设置方式如下:
if (req->rq_export && req->rq_export->exp_in_recovery) {//server正在恢复 newdl = cfs_time_current_sec() +
req->rq_export->exp_obd->obd_recovery_timeout; } else {
if (extra_time) {
extra_time += cfs_time_current_sec() -
req->rq_arrival_time.tv_sec; at_add(&svc->srv_at_estimate, extra_time); }
newdl = req->rq_arrival_time.tv_sec + at_get(&svc->srv_at_estimate); }
--如果(req->rq_deadline >= newdl)则返回-ETIMEDOUT,怎么看都觉得不对劲啊???? --分配并初始化reqcopy和reqmsg
--如果req->rq_sent_final则表示已经发送响应了,所以没必要发送early reply了 --lustre_pack_reply_flags(reqcopy, 1, NULL, NULL, LPRFL_EARLY_REPLY) --ptlrpc_send_reply(reqcopy, PTLRPC_REPLY_EARLY)
--如果ptlrpc_send_reply返回为0,则表示发送early reply成功,修改req->rq_deadline = newdl
--ptlrpc_req_drop_rs(reqcopy): Free the (early) reply state
ptlrpc_server_drop_request(struct ptlrpc_request *req)
--首先获取ptlrpc_request_buffer_desc和ptlrpc_service
struct ptlrpc_request_buffer_desc *rqbd = req->rq_rqbd;//ptlrpc_request是如何与 ptlrpc_request_buffer_desc建立联系的????见request中重要域的初始化 struct ptlrpc_service *svc = rqbd->rqbd_service; --如果!atomic_dec_and_test(&req->rq_refcount)则直接返回
--修改ptlrpc_service::srv_n_active_reqs;添加该请求到ptlrpc_request_buffer_desc:: rqbd_reqs链表,代码如下: svc->srv_n_active_reqs--;
list_add(&req->rq_list, &rqbd->rqbd_reqs);
--关于该函数的理解留待后期完成,现在还是有些不明白。。。。。????
Request中重要域的初始化 ptlrpc_request::rq_svc_thread--- 在ptlrpc_server_handle_request函数中会传递参数 ptlrpc_thread,该参数将赋值给ptlrpc_request::rq_svc_thread。
ptlrpc_request::rq_arrival_time ---在ptlrpc_init_svc---> ptlrpc_grow_req_bufs---> ptlrpc_alloc_rqbd---> rqbd->rqbd_cbid.cbid_fn = request_in_callback, request_in_callback调用do_gettimeofday (&req-> rq_arrival_time)获取request的到达时间 ptlrpc_request::rq_rqbd--- 同样是在request_in_callback中,如下代码:
struct ptlrpc_request_buffer_desc *rqbd = cbid->cbid_arg req->rq_rqbd = rqbd ptlrpc_request::rq_xid---同样是在request_in_callback中,如下代码:
req->rq_xid = ev->match_bits;但是这个到底是咋回事,不得而知,我们不一定也得这样。。
看了上面“request中重要域的初始化”,我们知道request_in_callback很重要。!!!!!
Request_in_callback是如何触发的呢?原理是:ptlrpc_init--->ptlrpc_init_portals---> ptlrpc_ni_init--->LNetEQAlloc(1024, ptlrpc_master_callback, &ptlrpc_eq_h)--->callback,这里的callback可能就是request_in_callback。通过上面我们看到在ptlrpc_alloc_rqbd中指定request到来时的回调函数为request_in_callback,而在ptlrpc接收到事件通知的时候,就将触发该callback。这对于我们设计的启示是什么???
前面我们提到ptlrpc_service::srv_idle_rqbds和ptlrpc_service::srv_active_rqbds问题,这里讲解:
我们在ptlrpc_init_svc--->ptlrpc_grow_req_bufs中先调用ptlrpc_alloc_rqbd分配ptlrpc_request_buffer_desc结构,然后每当分配一次成功就调用ptlrpc_server_post_idle_rqbds ,该函数遍历ptlrpc_service::srv_idle_rqbds链表,将其中的ptlrpc_request_buffer_desc依次转移到ptlrpc_service::srv_active_rqbds链表,并调用ptlrpc_register_rqbd(rqbd)这应该就是所谓的内存注册吧???所以在我们的设计中没有这个逻辑。
Ost启动后又是如何与llog_ctxt建立关系的呢? 与ost相关的llog_ctxt有:
LLOG_MDS_OST_ORIG_CTXT和LLOG_MDS_OST_REPL_CTXT 与LLOG_MDS_OST_ORIG_CTXT相关的函数调用为:
Lov_log.c: lov_llog_init----llog_setup(obd, LLOG_MDS_OST_ORIG_CTXT, tgt, 0, NULL, &lov_mds_ost_orig_logops)
Mds_log.c: mds_llog_init-----llog_setup(obd, LLOG_MDS_OST_ORIG_CTXT, tgt, 0, NULL, &mds_ost_orig_logops)
Osc_request.c: osc_llog_init-------llog_setup(obd, LLOG_MDS_OST_ORIG_CTXT, tgt, count, &catid->lci_logid, &osc_mds_ost_orig_logops) 与LLOG_MDS_OST_REPL_CTXT相关的函数调用为:
Filter.c: filter_llog_init----llog_setup(obd, LLOG_MDS_OST_REPL_CTXT, tgt, 0, NULL, &filter_mds_ost_repl_logops)
那么这些llog_ctxt是如何建立起来的呢?如下: Server_fill_super
--server_start_targets
--lustre_process_log(sb, lsi->lsi_ldd->ldd_svname, &cfg):通过config信息启动targets,该函 数主要是处理config log的,针对不同的设备有不同的***__process_config.在client端 ll_fill_super中也会调用lustre_process_log。关于lustre_process_log--->obd_process_config --->***_process_config的路径我们将在后面分析。
--如果lustre_process_log返回成功则执行如下代码:
obd = class_name2obd(lsi->lsi_ldd->ldd_svname)
obd_notify(obd, NULL, OBD_NOTIFY_CONFIG, (void *)CONFIG_LOG)
首先获得对应的targets 设备(OST/MDT)???,然后调用obd_notify,原型如下: obd_notify(struct obd_device *obd,
struct obd_device *watched,
enum obd_notify_event ev, void *data)
这里data传递的是CONFIG_LOG表示finished processing config log,另外还有 CONFIG_SYNC,CONFIG_TARGET。Obd_notify会调用设备对应的notify函数,这里
但是源码中不存在mdt_notify和ost_nofity,只存在mds_notify(这个对应于mds,也就 是说mdt是没有notify函数的)和 filter_notify(这个应该对应于ost???见源码中 注释。。。也就是说oss是没有notify函数的)。难道因为我们先启动mds,所以先走 mds_notify?????但是http://www.linuxjournal.com/content/lustre-distributed-filesystem? page=0,2&utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A%20linuxjournalcom%20%28Linux%20Journal%20-%20The%20Original%20Magazine%20of%20the%20Linux%20Community%29 可知,当mount ost的时候,才会调用到mds_notify???,而且在mds_notify中第二个参数必须被指定,但是这里调用obd_notify的时候传递的是NULL,所以肯定不是调用mds_notify,那么唯一能解释的就是这里就是找mdt对应的notify函数,只可惜没有,所以不做什么事情。。。那么在哪里调用mds_notify呢?我们将在下面分析。。。
关于mds_notify分析如下:
Mds_notify --
mds_lov_start_synchronize --mds_lov_synchronize --__mds_lov_synchronize
--mds_lov_update_mds --mds_lov_update_desc --llog_cat_initialize
mds_llog_init
--struct obd_device *lov_obd = obd->u.mds.mds_osc_obd
--llog_setup(obd, LLOG_MDS_OST_ORIG_CTXT, tgt, 0, NULL,
&mds_ost_orig_logops) 启动mds自身log
--obd_llog_init(lov_obd, tgt, count, logid, uuid) 启动lov log? --lov_llog_init
llog_process(struct llog_handle *loghandle, llog_cb_t cb, void *data, void *catdata) llog_process_thread(void *arg)
class_config_llog_handler(struct llog_handle * handle,
struct llog_rec_hdr *rec, void *data)
--class_process_config(struct lustre_cfg *lcfg)
--obd_process_config(struct obd_device *obd, int datalen, void *data) --
server_fill_super---> server_start_targets ---> lustre_start_simple(LUSTRE_MDS_OBDNAME,...) ---> do_lcfg(obdname, 0, LCFG_SETUP, s1, s2, 0, 0) ---> class_process_config ---> class_setup(obd, lcfg)----> mds_setup,但是如果走得是这条路径则lcfg->lcfg_bufcount == 3,不满足if (lcfg->lcfg_bufcount >= 4 && LUSTRE_CFG_BUFLEN(lcfg, 3) > 0) 这个条件,所以不会执行strncpy(mds->mds_profile, lustre_cfg_string(lcfg, 3),LUSTRE_CFG_BUFLEN(lcfg, 3));也就是说不会对mds->mds_profile赋值,这样在mds_postsetup中就不会执行mds_lov_connect,那么到底何时建立mds和lov的关系呢???或许Mds和lov建立关系,不是在mds_lov_connect中呢???在分析完mds_setup后分析。。。
mds_setup(struct obd_device *obd, obd_count len, void *buf):这个过程和mgs_setup相似
--lmi = server_get_mount(obd->obd_name) --lsi = s2lsi(lmi->lmi_sb);
--obd->obd_fsops = fsfilt_get_ops(MT_STR(lsi->lsi_ldd)); --obd->obd_namespace = ldlm_namespace_new(obd, ns_name, LDLM_NAMESPACE_SERVER, LDLM_NAMESPACE_GREEDY);
--mds_fs_setup(obd, mnt)
--if (lcfg->lcfg_bufcount >= 4 && LUSTRE_CFG_BUFLEN(lcfg, 3) > 0){
...
//初始化mds->mds_profile,该域在mds_postsetup--->mds_lov_connect中会用到 strncpy(mds->mds_profile, lustre_cfg_string(lcfg, 3),
LUSTRE_CFG_BUFLEN(lcfg, 3)); }
--ptlrpc_init_client(LDLM_CB_REQUEST_PORTAL, LDLM_CB_REPLY_PORTAL, \"mds_ldlm_client\--mds_postsetup(obd)
--llog_setup(obd, LLOG_CONFIG_ORIG_CTXT, obd, 0, NULL, &llog_lvfs_ops);
--llog_setup(obd, LLOG_LOVEA_ORIG_CTXT, obd, 0, NULL, &llog_lvfs_ops);
--如果if (mds->mds_profile) 则调用mds_lov_connect(obd, lprof->lp_osc)
在mds_lov_connect中:
--如果if (mds->mds_osc_obd)则直接返回
--否则mds->mds_osc_obd = class_name2obd(lov_name),这里的mds_osc_obd 就是lov
--mds_lov_read_objids(obd)
--obd->obd_no_conn = 1:在我们确认有OSTs之前拒绝新的client连接请求 --obd_register_observer(mds->mds_osc_obd, obd) 注册mds作为lov obd的 observer
--obd_connect(&conn, mds->mds_osc_obd, &obd->obd_uuid, data, &mds->mds_osc_exp):关联mds和lov,并返回conn和mds->mds_osc_exp, 这里mds->mds_osc_exp就是作为lov在mds端的代理
mgs_write_log_target(struct obd_device *obd,struct mgs_target_info *mti)
--mgs_write_log_mdt/mgs_write_log_ost(struct obd_device *obd, struct fs_db *fsdb, struct mgs_target_info *mti)
server_fill_super(struct super_block *sb)
--server_kernel_mount(sb): mount using mount options
--if (class_name2obd(lsi->lsi_ldd->ldd_svname)) 表明mgs已经启动,退出 --server_start_mgs(struct super_block *sb)
--server_find_mount(LUSTRE_MGS_OBDNAME):首先检查是否已经有关于mgs的 mount info 在全局的server_mount_info_list链表中,所有执行过 server_register_mount 的obd_device都有一个对应的struct lustre_mount_info结构 在全局server_mount_info_list 链表中。如果在,则直接返回,表明mgs已经启 动了。
--server_register_mount(LUSTRE_MGS_OBDNAME, sb, mnt):这里会产生一个关于 mgs的mount_info,并添加到server_mount_info_list链表中。
--lustre_start_simple(LUSTRE_MGS_OBDNAME, LUSTRE_MGS_NAME,
LUSTRE_MGS_OBDNAME, 0, 0) 启动mgs,注意这里要总结一下:所有的server(mgs,mds,oss)的启动都是通 过lustre_start_simple启动的,lustre_start_simple的调用关系下面讲解。 --lustre_start_mgc(sb)
--
--server_start_targets(sb, mnt):启动mdt或者ost --server_fill_super_common(struct super_block *sb)
Lustre_start_simple调用关系:
lustre_start_simple(char *obdname, char *type, char *uuid,char *s1, char *s2)
--do_lcfg(obdname, 0, LCFG_ATTACH, type, uuid, 0, 0) --do_lcfg(obdname, 0, LCFG_SETUP, s1, s2, 0, 0)
--声明struct lustre_cfg_bufs bufs结构 --lustre_cfg_bufs_set_string:设置bufs
--lustre_cfg_new:通过bufs创建新的lustre_cfg结构 --class_process_config(struct lustre_cfg *lcfg)
--根据lcfg->lcfg_command决定执行什么操作,switch(lcfg->lcfg_command) --如果是LCFG_ATTACH,则执行class_attach --如果是LCFG_SETUP则执行class_setup --如果是其他命令则执行相应的操作
我们先关注mgs_setup,因为我们直接承接上文中
lustre_start_simple ( LUSTRE_MGS_OBDNAME, LUSTRE_MGS_NAME,
LUSTRE_MGS_OBDNAME, 0, 0);
在lustre_start_simple中只有LCFG_ATTACH和LCFG_SETUP两个命令,所以我们知道肯定会调用mgs_setup,于是我们就看看mgs_setup的调用关系: mgs_setup(struct obd_device *obd, obd_count len, void *buf)
--server_get_mount(obd->obd_name):首先获取关于mgs的lustre_mount_info信息 --struct vfsmount *mnt = lmi->lmi_mnt; struct lustre_sb_info *lsi = s2lsi(lmi->lmi_sb);
--obd->obd_fsops = fsfilt_get_ops(MT_STR(lsi->lsi_ldd)): 根据底层文件系统(可以从 lsi->lsi_ldd获知)获取obd->obd_fsops(属于struct fsfilt_operations类型),如果给定文 件系统的fsfilt_operations是空的,则试图加载该模块并重新查找。
--ldlm_namespace_new(obd, \"MGS\
LDLM_NAMESPACE_MODEST) 为mgs创建关于分布式锁的命名空间???? --mgs_fs_setup(obd, mnt)
--cleanup_group_info()
--fsfilt_setup(obd, mgs->mgs_sb)实际上调用obd->obd_fsops->fs_setup() --push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL)
--simple_mkdir(cfs_fs_pwd(current->fs), mnt, MOUNT_CONFIGS_DIR, 0777, 1) 这 里创建配置文件所在的目录
--mgs->mgs_configs_dir = dentry
--lookup_one_len(\"__iopen__\cfs_fs_pwd(current->fs),strlen(\"__iopen__\")):dir for fid2dentry
--mgs->mgs_fid_de = dentry
-pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL)
--llog_setup(obd, LLOG_CONFIG_ORIG_CTXT, obd, 0, NULL,&llog_lvfs_ops) 启动配置 日志
--初始化mgs服务:mgs->mgs_service = ptlrpc_init_svc(...,mgs_handle,...);
--ptlrpc_start_threads(obd, mgs->mgs_service):启动多个线程执行mgs->mgs_service --ping_evictor_start():启动ping evictor
这里在ptlrpc_init_svc中我们传递给mgs的处理函数为mgs_handle,当mgs接收到请求时就由该函数执行。下面我们关注的是所有的obd_device的注册过程,以及各个obd_device之间建立关系的过程,这里会回答上面提到的mds和lov之间建立关系的过程。
当mgs收到MGS_CONNECT消息时,将调用target_handle_connect。而这个消息是由如下路径发送的:mgc_setup--->client_obd_setup--->指定connect_op = MGS_CONNECT,然后指定imp->imp_connect_op = connect_op,将connect_op赋值给import,这里有什么用,后面将看到:
Lustre_start_mgc--->obd_connect(&mgc_conn, obd, &(obd->obd_uuid), data, &exp)这里对应的
是mgc_obd_ops中的client_connect_import。
Ll_fill_super--->client_common_fill_super--->obd_connect(&mdc_conn, obd, &sbi->ll_sb_uuid, data, &sbi->ll_mdc_exp)和obd_connect(&osc_conn, obd, &sbi->ll_sb_uuid, data, &sbi->ll_osc_exp),这里两个obd_connect分别针对的是mdc和osc,obd_connect相应函数为client_connect_import和client_connect_import(注意在调用这两个obd_connect之前都先调用了class_name2obd来获取obd,先是class_name2obd(mdc),后是class_name2obd(osc),所以这里两个obd是不同的,分别对应mdc_obd和osc_obd)。
在client_connect_import中: Client_connect_import
--class_connect(dlm_handle, obd, cluuid) --class_conn2export --ldlm_namespace_new --ptlrpc_init_import(imp)
--ptlrpc_connect_import(imp, NULL):在这里准备rpc请求并发送请求,与server建立连 接,此时我们在mgc_setup--->client_obd_setup--->指定connect_op = MGS_CONNECT, 然后指定imp->imp_connect_op = connect_op,将connect_op赋值给import,就派上用 场了,因为我们在ptlrpc_prep_req中有参数imp->imp_connect_op,这样请求到达mgs 端,被mgs_handle处理,将调用target_handle_connect。 同理对于mdc和osc和mgc类似,在此不再赘述。
上面的三种(mgc,mdc,osd)都是和相应的mgs,mds,oss建立连接时分别调用client_connect_import,client_connect_import,client_connect_import。
那么mds和lov,lov和osc是如何建立关系的呢?如下:
Mds_setup--->mds_postsetup--->mds_lov_connect(调用该函数是有前提的),在mds_lov_connect中,首先获取lov设备:mds->mds_osc_obd = class_name2obd(lov_name),这里虽然名称为mds->mds_osc_obd,实际上是lov。然后注册mds为lov的observer:obd_register_observer(mds->mds_osc_obd, obd),这里的obd就是mds。接着调用obd_connect(&conn, mds->mds_osc_obd, &obd->obd_uuid, data, &mds->mds_osc_exp),这里实际上是调用lov_connect,在lov_connect中又会针对lov中lov->desc.ld_tgt_count个Lov_tgt_desc调用lov_connect_obd(obd, i, lov->lov_tgts[i]->ltd_activate,&lov->lov_ocd),这里的lov_connect_obd执行如下: Lov_connect_obd
--class_find_client_obd(&tgt_uuid, LUSTRE_OSC_NAME,
&obd->obd_uuid); --obd_register_observer(tgt_obd, obd)
--obd_connect(&conn, tgt_obd, &lov_osc_uuid, data, &lov->lov_tgts[index]->ltd_exp)
--osc_connect???所以在这里纠结的是这里obd_connect到底调用的是什么呢?如果说是 osc_connect,之前在client_common_fill_super中已经调用过了啊?但是在 client_common_fill_super中可能仅仅是client启动的时候调用一次,后来因为一个client 可能和多个ost交互,所以这里涉及到lov的概念,于是就有了client为lov管理的所有
的osc和ost建立连接。
所以接下来我们关注的是:
(1)第一次client_common_fill_super中调用osc_connect关于osc_conn以及sbi->ll_osc_exp的初始化
(2)Mds_setup--->mds_postsetup--->mds_lov_connect路径中,mds->mds_osc_obd是何时被初始化的,又是如何初始化的?
(3)Lov是如何管理多个osc的,也就是lov的lov_tgt_desc和lov_desc是如何建立的
(1)
Client端的启动流程如下: A:Init_obdclass
--class_handle_init() --obd_init_caches()
--lustre_register_fs():这里讲lustre接入到vfs中 B:ptlrpc_init C:osd_init
--lquota_init
--class_register_type(&osc_obd_ops, lvars.module_vars,LUSTRE_OSC_NAME) D:mdc_init E:lov_init
F:lustre_fill_super
--lustre_init_lsi() --lmd_parse
--lustre_start_mgc:下面会分析 --ll_fill_super
--。。。。
--client_common_fill_super:下面会分析
client_common_fill_super实现如下:
client_common_fill_super(struct super_block *sb,char *mdc, char *osc)
--obd = class_name2obd(mdc):确认MDC已经setup了
--obd_connect(&mdc_conn, obd, &sbi->ll_sb_uuid, data, &sbi->ll_mdc_exp):与MDS 建立连接并返回mdc_conn和sbi->ll_mdc_exp。
--obd = class_name2obd(osc):确认OSC已经setup了
--obd_connect(&osc_conn, obd, &sbi->ll_sb_uuid, data, &sbi->ll_osc_exp):与OSS建 立连接并返回osc_conn和sbi->ll_osc_exp
下面我们看mdc和osc都是在何时建立的呢?Obd_connect又是如何实现的呢? ll_fill_super(struct super_block *sb)
--lsi->lsi_llsbi = sbi = ll_init_sbi()
--char *profilenm = get_profile_name(sb):lmd->lmd_profile只针对client才有 --声明并初始化struct config_llog_instance cfg = {0, } sprintf(ll_instance, \"%p\ cfg.cfg_instance = ll_instance;
cfg.cfg_uuid = lsi->lsi_llsbi->ll_sb_uuid; cfg.cfg_sb = sb;
--lustre_process_log(sb, profilenm, &cfg):profile在前面调用get_profile_name获得
--变量声明或者初始化
struct lustre_cfg *lcfg; struct lustre_cfg_bufs bufs;
struct lustre_sb_info *lsi = s2lsi(sb); struct obd_device *mgc = lsi->lsi_mgc; --设置lustre_cfg_bufs
lustre_cfg_bufs_reset(&bufs, mgc->obd_name);
lustre_cfg_bufs_set_string(&bufs, 1, logname):这里指定logname就是上面 的profilename
lustre_cfg_bufs_set(&bufs, 2, cfg, sizeof(*cfg)); lustre_cfg_bufs_set(&bufs, 3, &sb, sizeof(sb));
--lcfg = lustre_cfg_new(LCFG_LOG_START, &bufs):根据bufs生成lustre_cfg
--obd_process_config(mgc, sizeof(*lcfg), lcfg):很显然是在这里处理日志,启动mdc和osc,后面会更加详细分析ll_fill_super--->lustre_process_log--->obd_process_config逻辑。
--lustre_cfg_free(lcfg)
--lprof = class_get_profile(profilenm):获取lprof,下面会用到
--sprintf(osc, \"%s-%s\:这里生成字符串osc --sprintf(mdc, \"%s-%s\:这里生成字符串mdc
--client_common_fill_super(sb, mdc, osc):上面的mdc和osc作为参数用于在 client_common_fill_super中检查mdc或者osc是否建立
lustre_fill_super(struct super_block *sb, void *data, int silent)
--lsi = lustre_init_lsi(sb)
--lmd_parse(char *options, struct lustre_mount_data *lmd):根据mount的options获得lmd
--struct lustre_mount_data *raw = (struct lustre_mount_data *)options --下面这个代码只对client有???这要看mount.lustre的实现过程 s1 = strstr(devname, \":/\"); if (s1) {
++s1;
lmd->lmd_flags = LMD_FLG_CLIENT; /* Remove leading /s from fsname */ while (*++s1 == '/') ;
/* Freed in lustre_free_lsi */
OBD_ALLOC(lmd->lmd_profile, strlen(s1) + 8); if (!lmd->lmd_profile)
RETURN(-ENOMEM);
sprintf(lmd->lmd_profile, \"%s-client\在这里初始化 lmd->lmd_profile,lmd->lmd_profile将在ll_fill_super中使用
}
--下面一段代码对client和server均有
OBD_ALLOC(lmd->lmd_dev, strlen(devname) + 1); if (!lmd->lmd_dev)
RETURN(-ENOMEM); strcpy(lmd->lmd_dev, devname); --lmd_print(lmd):
--PRINT_CMD(PRINT_MASK, \" mount data:\\n\") --只对client才有的语句: if (lmd_is_client(lmd))
PRINT_CMD(PRINT_MASK, \"profile: %s\\n\
-- PRINT_CMD(PRINT_MASK, \"device: %s\\n\ PRINT_CMD(PRINT_MASK, \"flags: %x\\n\--如果指定了lmd->ops则打印: if (lmd->lmd_opts)
PRINT_CMD(PRINT_MASK, \"options: %s\\n\
--if (lmd_is_client(lmd)){
lustre_start_mgc(sb):该语句分析见下面
(*client_fill_super)(sb):这里的client_fill_super就是ll_fill_super }else{
server_fill_super(sb) }
如果是client端则先调用lustre_start_mgc,然后调用ll_fill_super,如果是server端则调 用server_fill_super
我们跟踪debug信息发现lmd_print打印如下(前面是server端的,后者是client端的): mount data:
device: /dev/ram0 flags: 0 mount data:
Profile:hust-client
device: 192.168.2.172@o2ib0:/hust
在上面分析过程中,在lustre_fill_super中,如果是client,则调用逻辑为: Lustre_fill_super
--lsi = lustre_init_lsi(sb)
--lmd_parse((char *)data, lmd)
--lmd_print(struct lustre_mount_data *lmd):根据打印信息显示为: Mount data:
Profile:hust-client----hust是我们mount client的时候文件系统名称
Device:192.168.2.172@o2ib:/hust ---- 192.168.2.172@o2ib:/hust 是我们在mount时 候指定的。 --lustre_start_mgc --client_fill_super
--ll_fill_super
--lsi->lsi_llsbi = sbi = ll_init_sbi()
--ll_pglist_init(sbi)
--lustre_process_log(sb, profilenm, &cfg) --client_common_fill_super(sb, mdc, osc)
--obd_connect(&mdc_conn, obd, &sbi->ll_sb_uuid, data, &sbi->ll_mdc_exp) --obd_connect(&osc_conn, obd, &sbi->ll_sb_uuid, data, &sbi->ll_osc_exp)
下面我们将详细分析该上下文中lustre_start_mgc,lustre_process_log,obd_connect的实现。 lustre_start_mgc(struct super_block *sb):下面分析中将只关注client相关代码
--len = strlen(LUSTRE_MGC_OBDNAME) + strlen(libcfs_nid2str(nid)) + 1 --OBD_ALLOC(mgcname, len):分配mgcname空间
--sprintf(mgcname, \"%s%s\:根据debug 信息可以看到类似MGC192.168.2.172@o2ib的信息
--obd = class_name2obd(mgcname):先检查是否已经存在mgc了,第一次应该不存在 --do_lcfg(mgcname, nid,LCFG_ADD_UUID, niduuid, 0,0,0):add mapping from uuid to nid --lustre_start_simple(mgcname, LUSTRE_MGC_NAME,
(char *)uuid->uuid, LUSTRE_MGS_OBDNAME, niduuid):启动mgc
--do_lcfg(obdname, 0, LCFG_ATTACH, type, uuid, 0, 0):会调用class_attach, class_attach又会调用设备相关的attach,但是mgc attach操作为NULL,后面会分 析class_attach的实现。
--do_lcfg(obdname, 0, LCFG_SETUP, s1, s2, 0, 0):调用class_setup--->mgc_setup后 面会分析class_setup,mgc_setup的实现。
--在do_lcfg和lustre_start_simple中都有关于日志的信息,该信息见该函数分析的后面。 --obd_connect(&mgc_conn, obd, &(obd->obd_uuid), data, &exp):和mgs建立连接??
--调用mgc对应的connect函数为client_connect_import,这里的mgc_conn和exp 是要从函数返回的,obd->obd_uuid是mgc对应的uuid,函数原型为:
client_connect_import(struct lustre_handle *dlm_handle,struct obd_device *obd, struct obd_uuid *cluuid, struct obd_connect_data *data, void *localdata)
--class_connect(dlm_handle, obd, cluuid)
--export = class_new_export(obd, cluuid):分配并初始化export
--class_handle_hash(&export->exp_handle, export_handle_addref):这是 class_new_export中的重要代码,代码主要是对export->exp_handle 进行初始化,并将该handle添加到hash表中
--conn->cookie = export->exp_handle.h_cookie:这里conn就是dlm_handle --*exp = class_conn2export(dlm_handle):根据dlm_handle的cookie去hash表 中查找对应的export
--export = class_handle2object(conn->cookie)
--在hash表中查找给定cookie对应的portals_handle @h,这里运用了 一点小技巧,class_handle2object返回的是portals_handle结构,但是 我们要的确是obd_export结构,我们却直接将portals_handle结构给 obd_export是因为portals_handle是obd_export中的第一个元素,呵 呵
--对找到的@h调用h->h_addref(h),对应的就是我们前面在 class_handle_hash中传递的是export_handle_addref函数, --obd->obd_namespace = ldlm_namespace_new(obd, obd->obd_name,
LDLM_NAMESPACE_CLIENT, LDLM_NAMESPACE_GREEDY)
--imp->imp_dlm_handle = *dlm_handle
--ptlrpc_init_import(imp)
--ptlrpc_connect_import(imp, NULL)
--import_select_connection(imp)
--ptlrpc_prep_req(imp, LUSTRE_OBD_VERSION, imp->imp_connect_op, 5, size, tmp)
--ptlrpcd_add_req(request):这是一个异步rpc请求,请求被添加到ptlrpcd queue中,由ptlrpcd_check->ptlrpc_check_set()发送。在某个时刻 ptlrpcd_check被调用,ptlrpcd_check调用关系如下:
Ptlrpcd_addref:我们在mgc_setup中调用的
--ptlrpcd_start(\"ptlrpcd\
--pc->pc_set = ptlrpc_prep_set():pc_set是ptlrpc_request_set类型 --cfs_kernel_thread(ptlrpcd, pc, 0)
--ptlrpcd(void *arg)
--struct ptlrpcd_ctl *pc = arg
--lwi = LWI_TIMEOUT(cfs_time_seconds(timeout ? timeout : 1),ptlrpc_expired_set, pc->pc_set):初始化lwi
--l_wait_event(pc->pc_set->set_waitq, ptlrpcd_check(pc), &lwi):等待事件发生,等待结束的条件是ptlrpcd_check 返回值不为0,下面我们会分析ptlrpcd_check。
--ptlrpc_pinger_add_import(imp)
--lsi->lsi_mgc = obd:keep the mgc info in the sb
在lustre_start_mgc中关于do_lcfg和lustre_start_simple debug信息:
(obd_config.c:788:class_process_config()) processing cmd: cf005-----LCFG_ADD_UUID (obd_config.c:799:class_process_config()) adding mapping from uuid MGC192.168.2.172@o2ib_0 to nid 0x50000c0a802ac (192.168.2.172@o2ib)
(obd_config.c:788:class_process_config()) processing cmd: cf001------LCFG_ATTACH (obd_config.c:146:class_attach()) Process entered
(obd_config.c:167:class_attach()) attach type mgc name: MGC192.168.2.172@o2ib uuid: 375f1a2f-178e-2f81-1def-f66a374f1b89
(genops.c:156:class_register_type()) Process entered
(obd_config.c:788:class_process_config()) processing cmd: cf003------LCFG_SETUP (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (mgc_request.c:539:mgc_setup()) Process entered
(obd_config.c:352:class_setup()) finished setup of obd MGC192.168.2.172@o2ib (uuid 375f1a2f-178e-2f81-1def-f66a374f1b89)
static int ptlrpcd_check(struct ptlrpcd_ctl *pc)
--将ptlrpc_req从pc->pc_set->set_new_requests链表中转移到pc->pc_set->set_requests链 表中,并更新set->set_remaining计数:
list_for_each_safe(pos, tmp, &pc->pc_set->set_new_requests) {
req = list_entry(pos, struct ptlrpc_request, rq_set_chain); list_del_init(&req->rq_set_chain); ptlrpc_set_add_req(pc->pc_set, req):在这里添加到set_requests链表并 更新set->set_remaining计数 rc = 1; }
--如果set->set_remaining不为0,则发送set->set_requests中所有尚未发送的请求,如下: if (pc->pc_set->set_remaining) {
rc = rc | ptlrpc_check_set(pc->pc_set):ptlrpc_check_set将发送 set->set_requests中的请求,如果所有都发送了则返回true
//对于所有的请求如果到了RQ_PHASE_COMPLETE阶段则从 set->set_requests中删除之,并调用ptlrpc_req_finished
list_for_each_safe(pos, tmp, &pc->pc_set->set_requests) {
req = list_entry(pos, struct ptlrpc_request,rq_set_chain); if (req->rq_phase != RQ_PHASE_COMPLETE) continue;
list_del_init(&req->rq_set_chain); req->rq_set = NULL; ptlrpc_req_finished (req); } }
--如果rc==0,但是pc->pc_set->set_new_requests链表不为空则rc=1; --返回rc
class_attach(struct lustre_cfg *lcfg)
--从lcfg中获取参数:
typename = lustre_cfg_string(lcfg, 1) name = lustre_cfg_string(lcfg, 0) uuid = lustre_cfg_string(lcfg, 2) --class_newdev(typename, name)
--struct obd_type *type = class_get_type(type_name)
--struct obd_type *type = class_search_type(name):首先在全局链表@obd_types 中查找,对于所有调用过class_register_type的模块都会在class_register_type 中调用list_add(&type->typ_chain, &obd_types)将该type 添加到全局链表 obd_types中。
--如果type为空,则调用request_module(modname)加载模块,代码如下: request_module(modname):在request_module中加载模块,会调用module_init, 这样就到了相应的模块的init函数中,对于这里就是到了mgc_init(我们在前 面讲client端启动流程的时候,看到了osc_init,lov_init, mdc_init,但是没有 看到mgc_init),在mgc_init中会调用class_register_type注册该类型。 --如果type为空,表示模块加载失败返回,否则调用obd_device_alloc,如下: Struct obd_device *newdev = obd_device_alloc()
--遍历全局的obd_devs数组,并将该newdev插入到obd_devs数组中。 --if (OBP(obd, attach))
--OBP(obd,attach)(obd, sizeof *lcfg, lcfg):对于mgc来说该函数为空
Lustre_fill_super-->lustre_start_mgc--->do_lcfg--->class_setup--->mgc_setup实现分析: class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
--if (!obd->obd_attached)或者if (obd->obd_set_up)都报错返回 --几个hash表的初始化:
obd->obd_uuid_hash = lustre_hash_init(\"UUID_HASH\
HASH_UUID_CUR_BITS, HASH_UUID_MAX_BITS, &uuid_hash_ops, 0);
obd->obd_nid_hash = lustre_hash_init(\"NID_HASH\
HASH_NID_CUR_BITS, HASH_NID_MAX_BITS, &nid_hash_ops, 0);
obd->obd_nid_stats_hash=lustre_hash_init(\"NID_STATS\ HASH_NID_STATS_CUR_BITS,
HASH_NID_STATS_MAX_BITS, &nid_stat_hash_ops, 0)
--初始化设备对应的obd_export exp = class_new_export(obd, &obd->obd_uuid) --obd_setup(obd, sizeof(*lcfg), lcfg):调用设备相关的setup
mgc_setup(struct obd_device *obd, obd_count len, void *buf)
--ptlrpcd_addref(void)
--ptlrpcd_start(\"ptlrpcd\
--ptlrpcd_start(\"ptlrpcd-recov\
--client_obd_setup(struct obd_device *obddev, obd_count len, void *buf)
--ldlm_get_ref():这里会调用ldlm_setup,该函数的打印信息非常多,多达上万行 --ptlrpc_init_client(rq_portal, rp_portal, name,&obddev->obd_ldlm_client):初始化 ptlrpc_client
--imp = class_new_import(obddev):生成一个新的obd_import --client_import_add_conn(imp, &server_uuid, 1) --obd_llog_init(obd, obd, 0, NULL, NULL)
--mgc_llog_init(struct obd_device *obd, struct obd_device *tgt, int count, struct llog_catid *logid, struct obd_uuid *uuid)
--llog_setup(obd, LLOG_CONFIG_ORIG_CTXT, tgt, 0, NULL,&llog_lvfs_ops) --llog_setup(obd, LLOG_CONFIG_REPL_CTXT, tgt, 0, NULL,&llog_client_ops)
Lustre_fill_super--->client_fill_super--->ll_fill_super--->lustre_process_log实现分析: lustre_process_log(struct super_block *sb, char *logname,struct config_llog_instance *cfg)
-- lustre_cfg_bufs_reset(&bufs, mgc->obd_name); lustre_cfg_bufs_set_string(&bufs, 1, logname); lustre_cfg_bufs_set(&bufs, 2, cfg, sizeof(*cfg)); lustre_cfg_bufs_set(&bufs, 3, &sb, sizeof(sb));
--lcfg = lustre_cfg_new(LCFG_LOG_START, &bufs); --obd_process_config(mgc, sizeof(*lcfg), lcfg)
--mgc_process_config(struct obd_device *obd, obd_count len, void *buf)
--这里我们传递的是LCFG_LOG_START命令,处理如下: --char *logname = lustre_cfg_string(lcfg, 1):logname是hust-client --cfg = (struct config_llog_instance *)lustre_cfg_buf(lcfg, 2) --sb = *(struct super_block **)lustre_cfg_buf(lcfg, 3)
--config_log_add(logname, cfg, sb):Add this log to our list of active logs --cld = config_log_find(logname, cfg):Find a config log by name
--mgc_process_log(struct obd_device *mgc,struct config_llog_data *cld):该函数 从mgs获取config log并处理之。前面已分析,下面再次分析。
--config_log_put(cld)
--lustre_cfg_free(lcfg)
mgc_process_log(struct obd_device *mgc,struct config_llog_data *cld)
--ctxt = llog_get_context(mgc, LLOG_CONFIG_REPL_CTXT)
--mgc_enqueue(mgc->u.cli.cl_mgc_mgsexp, NULL, LDLM_PLAIN, NULL, LCK_CR, &flags, NULL, NULL, NULL, cld, 0, NULL, &lockh):获取config lock
--class_config_parse_llog(ctxt, cld->cld_logname, &cld->cld_cfg):这里的 cld->cld_logname就是前面ll_fill_super中提到的profilenm。该profilenm对应的日志文 件中暂时还没有日志记录???
--struct llog_handle *llh
--llog_create(ctxt, &llh, NULL, name):对应于llog_client_ops::llog_client_create
--llog_client_create(struct llog_ctxt *ctxt, struct llog_handle **res,
struct llog_logid *logid, char *name)
--handle = llog_alloc_handle():本地分配llog_handle --*res = handle:通过参数返回
--ptlrpc_prep_req(imp, LUSTRE_LOG_VERSION,
LLOG_ORIGIN_HANDLE_CREATE, bufcount, size, bufs):准 备rpc请求,命令为LLOG_ORIGIN_HANDLE_CREATE,rpc请求中参 数包括log id,log ctxt和log name。
--ptlrpc_queue_wait(req):发送rpc请求并等待返回
--handle->lgh_id = body->lgd_logid:这里body->lgd_logid是从rpc返回的 --handle->lgh_ctxt = ctxt:这里ctxt是参数传递过来的
--llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL)
--llog_read_header(handle):实际调用llog_client_read_header
--llog_client_read_header(struct llog_handle *handle)
--ptlrpc_prep_req(imp, LUSTRE_LOG_VERSION,
LLOG_ORIGIN_HANDLE_READ_HEADER, 2, size, NULL) --准备rpc请求中的llogd_body
body = lustre_msg_buf(req->rq_reqmsg, REQ_REC_OFF, sizeof(*body));
body->lgd_logid = handle->lgh_id;
body->lgd_ctxt_idx = handle->lgh_ctxt->loc_idx - 1; body->lgd_llh_flags = handle->lgh_hdr->llh_flags; --ptlrpc_queue_wait(req) --ptlrpc_req_finished(req)
--llog_process(llh, class_config_llog_handler, cfg, &cd)
--声明并初始化llog_process_info结构。
struct llog_process_info *lpi
lpi->lpi_loghandle = loghandle; lpi->lpi_cb = cb; lpi->lpi_cbdata = data; lpi->lpi_catdata = catdata; --llog_process_thread(void *arg)
--从参数中获取llog_process_info,进而获取llog_handle,llog_log_hdr等 struct llog_process_info *lpi = (struct llog_process_info *)arg; struct llog_handle *loghandle = lpi->lpi_loghandle; struct llog_log_hdr *llh = loghandle->lgh_hdr; struct llog_process_cat_data *cd = lpi->lpi_catdata;
--对llog_handle中的每条日志记录进行处理,这里采用的是以 LLOG_CHUNK_SIZE为单位进行读取,然后对该单位长度中的所有记录 进行处理。代码如下:
--llog_next_block(loghandle, &saved_index, index, &cur_offset, buf, LLOG_CHUNK_SIZE):读取最多LLOG_CHUNK_SIZE长度的日志 记录到buf中。
--对buf中的每一条记录处理
for (rec = (struct llog_rec_hdr *)buf;
(char *)rec < buf + LLOG_CHUNK_SIZE;
rec = (struct llog_rec_hdr *)((char *)rec + rec->lrh_len)){
.....
lpi->lpi_cb(loghandle, rec,lpi->lpi_cbdata):在这里,这个函数就是mgc_process_log--->llog_process中传递class_config_llog_handler ,该函数前面已经讲解过。 }
--llog_close(llh)
class_config_llog_handler处理的记录类型都是OBD_CFG_REC类型的日志,在class_config_llog_handler的最后会执行class_process_config。根据debug信息,在上面的处理中调用class_config_llog_handler--->class_process_config: class_process_config(struct lustre_cfg *lcfg)
--CDEBUG(D_IOCTL, \"processing cmd: %x\\n\--switch(lcfg->lcfg_command) { case LCFG_ATTACH: {//0414
err = class_attach(lcfg); GOTO(out, err); }
case LCFG_MARKER: {//
struct cfg_marker *marker;
marker = lustre_cfg_buf(lcfg, 1);
CDEBUG(D_IOCTL, \"marker %d (%#x) %.16s %s\\n\ marker->cm_flags, marker->cm_tgtname, marker->cm_comment); GOTO(out, err = 0); }
case LCFG_MOUNTOPT: {
CDEBUG(D_IOCTL, \"mountopt: profile %s osc %s mdc %s\\n\ lustre_cfg_string(lcfg, 1), lustre_cfg_string(lcfg, 2), lustre_cfg_string(lcfg, 3));
/* set these mount options somewhere, so ll_fill_super * can find them. */
err = class_add_profile(LUSTRE_CFG_BUFLEN(lcfg, 1), lustre_cfg_string(lcfg, 1),
LUSTRE_CFG_BUFLEN(lcfg, 2), lustre_cfg_string(lcfg, 2),
LUSTRE_CFG_BUFLEN(lcfg, 3), lustre_cfg_string(lcfg, 3)); GOTO(out, err); }
case LCFG_SETUP: {//0414
err = class_setup(obd, lcfg); GOTO(out, err); }
default: {//默认调用obd_process_config,对于LCFG_LOV_***等操作都是调用 obd_process_config--->lov_process_config处理的
err = obd_process_config(obd, sizeof(*lcfg), lcfg); GOTO(out, err);
} }
打印信息包括(我们会根据打印信息分析设计与实现): 通过下面的debug信息可知:
LCFG_MARKER是成对出现的,成对的两个LCFG_MARKER之间都是关于同一个设备的config信息,LCFG_MARKER标识配置的开始或结束;
LCFG_MARKER的处理中,打印信息为CDEBUG(D_IOCTL, \"marker %d (%#x) %.16s %s\\n\marker->cm_flags, marker->cm_tgtname, marker->cm_comment),其中marker->cm_flags=1表示CM_START,为2表示CM_END,也就是说1,2分别表示某设备配置日志的开始和结束。Marker->cm_tgtname则是在mgs端写入日志记录时记录对应的target信息。Marker->cm_comment则表示提示信息,这些提示信息包括“lov setup”,“add mdt”,“add mdc”,“add ost”,“add osc”,“add failnid”等。Marker相
关的参数都是在record_marker中指定的,如:
record_marker(obd, llh, fsdb, CM_START, lovname, \"lov setup\") record_marker(obd, llh, fsdb, CM_END, lovname, \"lov setup\"),这里的lovname就是hust-clilov
Client端lov的配置处理:
(obd_config.c:788:class_process_config()) processing cmd: cf010
(obd_config.c:857:class_process_config()) marker 3 (0x1) hust-clilov lov setup
(obd_config.c:788:class_process_config()) processing cmd: cf001
(obd_config.c:167:class_attach()) attach type lov name: hust-clilov-ffff81001cad6400 uuid: 4181fdc6-a186-9fbb-c61d-e0694ea21ef9
(obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (lov_obd.c:841:lov_setup()) Process entered
(obd_config.c:352:class_setup()) finished setup of obd hust-clilov-ffff81001cad6400 (uuid 4181fdc6-a186-9fbb-c61d-e0694ea21ef9)
(obd_config.c:788:class_process_config()) processing cmd: cf010
(obd_config.c:857:class_process_config()) marker 3 (0x2) hust-clilov lov setup
Client端Mdc的配置处理:
(obd_config.c:788:class_process_config()) processing cmd: cf010
(obd_config.c:857:class_process_config()) marker 4 (0x1) hust-MDT0000 add mdc
(obd_config.c:788:class_process_config()) processing cmd: cf005
(obd_config.c:799:class_process_config()) adding mapping from uuid 192.168.2.172@o2ib to nid 0x50000c0a802ac (192.168.2.172@o2ib)
(obd_config.c:788:class_process_config()) processing cmd: cf005
(obd_config.c:799:class_process_config()) adding mapping from uuid 192.168.2.172@o2ib to nid 0x20000c0a803ac (192.168.3.172@tcp)
(obd_config.c:788:class_process_config()) processing cmd: cf001
(obd_config.c:167:class_attach()) attach type mdc name: hust-MDT0000-mdc-ffff81001cad6400 uuid: 4181fdc6-a186-9fbb-c61d-e0694ea21ef9
(obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (mdc_request.c:1381:mdc_setup()) Process entered
(obd_config.c:352:class_setup()) finished setup of obd hust-MDT0000-mdc-ffff81001cad6400 (uuid 4181fdc6-a186-9fbb-c61d-e0694ea21ef9)
(obd_config.c:788:class_process_config()) processing cmd: cf007
(obd_config.c:816:class_process_config()) mountopt: profile hust-client osc hust-clilov mdc hust-MDT0000-mdc
(obd_config.c:671:class_add_profile()) Process entered
(obd_config.c:673:class_add_profile()) Add profile hust-client
(obd_config.c:788:class_process_config()) processing cmd: cf010
(obd_config.c:857:class_process_config()) marker 4 (0x2) hust-MDT0000 add mdc
Hust-OST0000对应的osc在本client的配置处理:
(obd_config.c:788:class_process_config()) processing cmd: cf010
(obd_config.c:857:class_process_config()) marker 8 (0x1) hust-OST0000 add osc
(obd_config.c:788:class_process_config()) processing cmd: cf005
(obd_config.c:799:class_process_config()) adding mapping from uuid 192.168.2.169@o2ib to nid 0x50000c0a802a9 (192.168.2.169@o2ib)
(obd_config.c:788:class_process_config()) processing cmd: cf005
(obd_config.c:799:class_process_config()) adding mapping from uuid 192.168.2.169@o2ib to nid 0x20000c0a803a9 (192.168.3.169@tcp)
(obd_config.c:788:class_process_config()) processing cmd: cf001
(obd_config.c:167:class_attach()) attach type osc name: hust-OST0000-osc-ffff81001cad6400 uuid: 4181fdc6-a186-9fbb-c61d-e0694ea21ef9
(obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (osc_request.c:4385:osc_setup()) Process entered
(obd_config.c:352:class_setup()) finished setup of obd hust-OST0000-osc-ffff81001cad6400 (uuid 4181fdc6-a186-9fbb-c61d-e0694ea21ef9)
(obd_config.c:788:class_process_config()) processing cmd: cf00d (obd_class.h:442:obd_process_config()) Process entered (lov_obd.c:1013:lov_process_config()) Process entered
(lov_obd.c:597:lov_add_target()) uuid:hust-OST0000_UUID idx:0 gen:1 active:1 (lov_pool.c:358:lov_ost_pool_add()) Process entered
(lov_obd.c:676:lov_add_target()) idx=0 ltd_gen=1 ld_tgt_count=1 (obd_class.h:1517:obd_notify()) Process entered (lov_obd.c:199:lov_notify()) Process entered
(obd_config.c:788:class_process_config()) processing cmd: cf010
(obd_config.c:857:class_process_config()) marker 8 (0x2) hust-OST0000 add osc
Hust-OST0001对应的osc在本client的配置处理:
(obd_config.c:788:class_process_config()) processing cmd: cf010
(obd_config.c:857:class_process_config()) marker 11 (0x1) hust-OST0001 add osc
(obd_config.c:788:class_process_config()) processing cmd: cf005
(obd_config.c:799:class_process_config()) adding mapping from uuid 192.168.2.169@o2ib to nid 0x50000c0a802a9 (192.168.2.169@o2ib)
(obd_config.c:788:class_process_config()) processing cmd: cf005
(obd_config.c:799:class_process_config()) adding mapping from uuid 192.168.2.169@o2ib to nid 0x20000c0a803a9 (192.168.3.169@tcp)
(obd_config.c:788:class_process_config()) processing cmd: cf001 (obd_config.c:146:class_attach()) Process entered
(obd_config.c:167:class_attach()) attach type osc name: hust-OST0001-osc-ffff81001cad6400 uuid: 4181fdc6-a186-9fbb-c61d-e0694ea21ef9
(obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (osc_request.c:4385:osc_setup()) Process entered
(obd_config.c:352:class_setup()) finished setup of obd hust-OST0001-osc-ffff81001cad6400 (uuid 4181fdc6-a186-9fbb-c61d-e0694ea21ef9)
(obd_config.c:788:class_process_config()) processing cmd: cf00d (obd_class.h:442:obd_process_config()) Process entered (lov_obd.c:1013:lov_process_config()) Process entered
(lov_obd.c:597:lov_add_target()) uuid:hust-OST0001_UUID idx:1 gen:1 active:1 (lov_pool.c:358:lov_ost_pool_add()) Process entered
(lov_obd.c:676:lov_add_target()) idx=1 ltd_gen=1 ld_tgt_count=2 (obd_class.h:1517:obd_notify()) Process entered (lov_obd.c:199:lov_notify()) Process entered
(obd_config.c:788:class_process_config()) processing cmd: cf010
(obd_config.c:857:class_process_config()) marker 11 (0x2) hust-OST0001 add osc
看了上面的debug信息,我们不禁要问这个操作的日志的日志文件名是什么呢? ll_fill_super
--lustre_process_log(根据lmd_print信息显示可知ll_fill_super传递给lustre_process_log 的参数profilenm是hust-client)
--lcfg = lustre_cfg_new(LCFG_LOG_START, &bufs) --obd_process_config(mgc, sizeof(*lcfg), lcfg)
--mgc_process_config(struct obd_device *obd, obd_count len, void *buf)
--mgc_process_log(obd, cld)
--class_config_parse_llog(ctxt, cld->cld_logname, &cld->cld_cfg)
--llog_create(ctxt, &llh, NULL, name)
--llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL) --llog_process(llh, class_config_llog_handler, cfg, &cd)
--class_config_parse_llog中的llog_create和llog_process都是涉 及rpc操作,到mgs端获取日志记录
--class_config_llog_handler
--class_process_config(lcfg_new):在这里真正的处理日 志记录
通过上面这个路径分析可知日志文件名为hust-client,那么该文件又是何时在mgs中创建并添加日志记录的呢?我们下面分析。这个就与mds/mgs端相关了。我们找出mds/mgs端所有与hust-client相关的信息:
当只有mds/mgs启动时,mds端关于hust-client相关信息: (mgs_llog.c:956:mgs_write_log_lov()) Writing log hust-client
当启动了ost的时候,mds端关于hust-client相关信息:
(mgs_llog.c:1171:mgs_write_log_osc()) adding osc for hust-OST0000 to log hust-client (mgs_llog.c:1171:mgs_write_log_osc()) adding osc for hust-OST0001 to log hust-client
当启动了mds,osd,client的时候,mds端关于hust-client的打印信息: 无;
接下来我们要看mgs_write_log_lov和mgs_write_log_osc中都写了什么内容?然后再回过头去看前面mgc_process_log调用路径中所有日志记录是怎么处理的。
下面的分析是根据模块加载时间驱动的,也就是先分析mdt,然后在ost。 lustre_fill_super(struct super_block *sb, void *data, int silent)
--server_fill_super(sb)
--lustre_start_mgc(sb):注意该函数在ll_fill_super中也会有 --server_start_targets(sb, mnt)
--lustre_start_simple:可能不执行,在启动target前先启动server --server_register_target(sb):向mgs注册
--obd_set_info_async(mgc->u.cli.cl_mgc_mgsexp,
sizeof(KEY_REGISTER_TARGET), KEY_REGISTER_TARGET,
sizeof(*mti), mti, NULL)
--mgc_target_register(exp, mti):传递MGS_TARGET_REG命令给 mgs,mgs在mgs_handle中处理函数为mgs_handle_target_reg(req), 在mgs端的处理下面讲解。
--server_register_mount(lsi->lsi_ldd->ldd_svname, sb, mnt) --lustre_process_log(sb, lsi->lsi_ldd->ldd_svname, &cfg)
--lustre_cfg_new(LCFG_LOG_START, &bufs):LCFG_LOG_START命令 --obd_process_config(mgc, sizeof(*lcfg), lcfg)
--mgc_process_config(struct obd_device *obd, obd_count len, void *buf)
--mgc_process_log(obd, cld)
--class_config_parse_llog(ctxt,cld->cld_logname,
&cld->cld_cfg)
--debug信息:looking up llog hust-MDT0000
--llog_create(ctxt, &llh, NULL, name):name为 hust-MDT0000
--llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL) --llog_process(llh, class_config_llog_handler, cfg, &cd)
关于执行到这里时llog_process的处理逻辑我们将分为当mdt mount的时候执行和ost_mount的时候的执行分别分析lustre-log-mdt-with-only-mds文件和lustre-log-2-ost-mounted。
当mdt mount的时候lustre_process_log--->obd_process_config--->mgc_process_config---> Mgc_process_log--->class_config_parse_llog---->llog_process分析: Lustre_process_log
--lustre_cfg_new(LCFG_LOG_START, &bufs):LCFG_LOG_START命令 --obd_process_config(mgc, sizeof(*lcfg), lcfg)
--mgc_process_config(struct obd_device *obd, obd_count len, void *buf)
--debug信息:parse_log hust-MDT0000 from 0 --mgc_process_log(obd, cld)
--ctxt = llog_get_context(mgc, LLOG_CONFIG_REPL_CTXT)
--mgc_enqueue(mgc->u.cli.cl_mgc_mgsexp, NULL, LDLM_PLAIN, NULL, LCK_CR, &flags, NULL, NULL, NULL, cld, 0, NULL, &lockh)
--lctxt = llog_get_context(mgc, LLOG_CONFIG_ORIG_CTXT)
--判断是否需要拷贝original llog到replica llog,对于mds和mgs在一起 的情况下不拷贝???所以这里我们使用的仍然是replica ctxt
--class_config_parse_llog(ctxt, cld->cld_logname, &cld->cld_cfg)
--这里使用的ctxt是LLOG_CONFIG_REPL_CTXT,其对应的处理函 数集合是llog_client_ops
--debug信息:looking up llog hust-MDT0000 --llog_create(ctxt, &llh, NULL, name):发送 LLOG_ORIGIN_HANDLE_CREATE命令给mgs,mgs_handle的处理 是llog_origin_handle_create。
--llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL) --llog_process(llh, class_config_llog_handler, cfg, &cd)
--llog_process_thread()
--llog_next_block()
--llog_client_next_block: 发送 LLOG_ORIGIN_HANDLE_NEXT_BLOCK命 令给mgs,mgs_handle的处理是 llog_origin_handle_next_block
--对于获取的每一个block中的每一条记录执行 lpi->lpi_cb(loghandle, rec,lpi->lpi_cbdata),在此这个函
数就是class_config_llog_handler,对于mdt mount的时候该函数处理了哪些日志记录,下面展示:
--class_process_config
Mdt mount的时候在class_config_llog_handler中日志处理信息展示:
(obd_config.c:1075:class_config_llog_handler()) Marker, inst_flg=0x8 mark_flg=0x1
(obd_config.c:788:class_process_config()) processing cmd: cf010
(obd_config.c:857:class_process_config()) marker 1 (0x1) hust-mdtlov lov setup
(obd_config.c:788:class_process_config()) processing cmd: cf001
(obd_config.c:167:class_attach()) attach type lov name: hust-mdtlov uuid: hust-mdtlov_UUID
(obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (lov_obd.c:841:lov_setup()) Process entered
(class_hash.c:101:lustre_hash_init()) Process entered (lov_pool.c:314:lov_ost_pool_init()) Process entered
(obd_config.c:352:class_setup()) finished setup of obd hust-mdtlov (uuid hust-mdtlov_UUID)
(obd_config.c:1075:class_config_llog_handler()) Marker, inst_flg=0x2 mark_flg=0x2 (obd_config.c:788:class_process_config()) processing cmd: cf010
(obd_config.c:857:class_process_config()) marker 1 (0x2) hust-mdtlov lov setup
(obd_config.c:788:class_process_config()) processing cmd: cf010
(obd_config.c:857:class_process_config()) marker 2 (0x1) hust-MDT0000 add mdt
(obd_config.c:788:class_process_config()) processing cmd: cf007
(obd_config.c:816:class_process_config()) mountopt: profile hust-MDT0000 osc hust-mdtlov mdc (obd_config.c:788:class_process_config()) processing cmd: cf001 (obd_config.c:167:class_attach()) attach type mds name: hust-MDT0000 uuid: hust-MDT0000_UUID (obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (handler.c:1937:mds_setup()) Process entered (obd_mount.c:169:server_get_mount()) Process entered (ldlm_resource.c:324:ldlm_namespace_new()) Process entered (ldlm_lockd.c:2079:ldlm_get_ref()) Process entered (ldlm_pool.c:851:ldlm_pool_init()) Process entered (mds_fs.c:725:mds_fs_setup()) Process entered (lvfs_linux.c:311:simple_mkdir()) creating directory ROOT (lvfs_linux.c:311:simple_mkdir()) creating directory PENDING (lvfs_linux.c:311:simple_mkdir()) creating directory LOGS (lvfs_linux.c:311:simple_mkdir()) creating directory OBJECTS (mds_fs.c:458:mds_init_server_data()) Process entered (handler.c:1858:mds_update_server_data()) Process entered (mds_lov.c:102:mds_lov_init_objids()) Process entered (handler.c:2145:mds_postsetup()) Process entered (llog_obd.c:155:llog_setup()) Process entered (obd_config.c:657:class_get_profile()) Process entered (mds_lov.c:670:mds_lov_connect()) Process entered (obd_class.h:1648:obd_register_observer()) Process entered (obd_class.h:1517:obd_notify()) Process entered (lov_obd.c:199:lov_notify()) Process entered (obd_class.h:719:obd_connect()) Process entered (lov_obd.c:382:lov_connect()) Process entered (obd_config.c:352:class_setup()) finished setup of obd hust-MDT0000 (uuid hust-MDT0000_UUID) (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 2 (0x2) hust-MDT0000 add mdt (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 5 (0x1) hust-MDT0000 mdt.group_upcall (obd_config.c:788:class_process_config()) processing cmd: cf00f (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 5 (0x2) hust-MDT0000 mdt.group_upcall 那么这些信息时何时被写入到日志文件hust-MDT0000/hust-client的呢?见下面分析: Mdt mount的时候记录日志-----mgc_write_log_mdt lustre_fill_super(struct super_block *sb, void *data, int silent)-----只分析主要逻辑 --server_fill_super(sb):server端mount的时候走这个路径 --server_kernel_mount(sb) --server_start_mgs(sb):这是当我们指定--mgs的时候才会执行 --lustre_start_mgc(sb) --server_start_targets(sb, mnt) --lustre_start_simple(LUSTRE_MDS_OBDNAME,.....) --server_register_target(sb):向mgs注册 --obd_set_info_async(mgc->u.cli.cl_mgc_mgsexp,sizeof(KEY_REGISTER_TAR GET), KEY_REGISTER_TARGET,sizeof(*mti), mti, NULL); --mgc_set_info_async():传递MGS_TARGET_REG命令,mgs_handle中 的处理函数为mgs_handle_target_reg(req),下面我们进入 mgs_handle_target_reg逻辑 --mgs_write_log_target(obd, mti) --mgs_write_log_mdt(obd, fsdb, mti):在这里写日志 --mgs_write_log_lov(...,fsdb->fsdb_mdtlov) --record_start_log(obd, &llh, mti->mti_svname) --record_marker --record_mount_opt --record_attach --record_setup --record_marker --record_end_log --name_create(&cliname, mti->mti_fsname, \"-client\") --mgs_write_log_lov(......,sdb->fsdb_clilov) --name_create(&mdcname, mti->mti_svname, \"-mdc\") --record_start_log(obd, &llh, cliname) --record_marker,record_attach,record_setup等 --record_end_log(obd, &llh) --mgs_write_log_params(obd, fsdb, mti) --lustre_process_log(sb, lsi->lsi_ldd->ldd_svname, &cfg) --server_fill_super_common(sb) 通过以上分析可知,lustre_fill_super是先在server_register_target中写日志记录到日志文件,然后在lustre_process_log中处理日志记录,从而attach/setup设备,或者关联设备(也就是各个设备之间建立关联,比如lov和osc的关联)。 mdt mount的时候处理日志文件----lustre_process_log 在server_register_target--->mgc_set_info_async--->mgs_handle_target_reg 中我们记录日志到日志文件hust-MDT0000和hust-client,在lustre_fill_super--->server_fill_super--->server_start_targets--->lustre_process_log中处理的是hust-MDT0000中的日志记录(至此hust-MDT0000中记录了hust-mdtlov记录 + mdt的记录 + hust-MDT0000的LCFG_PARAM记录),如何处理的呢?我们且看: server_start_targets(struct super_block *sb, struct vfsmount *mnt) --lustre_process_log(sb, lsi->lsi_ldd->ldd_svname, &cfg):第二个参数就是logname,这里 是hust-MDT0000 --lustre_cfg_new(LCFG_LOG_START, &bufs) --obd_process_config(mgc, sizeof(*lcfg), lcfg) --mgc_process_config:对LCFG_LOG_START命令的处理是mgc_process_log --llog_get_context(mgc, LLOG_CONFIG_REPL_CTXT) --mgc_enqueue(mgc->u.cli.cl_mgc_mgsexp, NULL, LDLM_PLAIN,....) --llog_get_context(mgc, LLOG_CONFIG_ORIG_CTXT) --class_config_parse_llog(ctxt, cld->cld_logname, &cld->cld_cfg) --llog_create(ctxt, &llh, NULL, name) --llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL) --llog_process(llh, class_config_llog_handler, cfg, &cd) --llog_process_thread(void *arg) --在此获取以block为单位的日志记录块,然后对于块中的 每一个记录调用class_config_llog_handler分别处理 --class_process_config:真正处理函数,我们看debug 信息: (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 1 (0x1) hust-mdtlov lov setup (obd_config.c:788:class_process_config()) processing cmd: cf001 (obd_config.c:167:class_attach()) attach type lov name: hust-mdtlov uuid: hust-mdtlov_UUID (genops.c:314:class_newdev()) Adding new device hust-mdtlov (ffff81049c8ca0f8) (obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (lov_obd.c:841:lov_setup()) Process entered (lov_pool.c:314:lov_ost_pool_init()) Process entered (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 1 (0x2) hust-mdtlov lov setup (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 2 (0x1) hust-MDT0000 add mdt (obd_config.c:788:class_process_config()) processing cmd: cf007 (obd_config.c:816:class_process_config()) mountopt: profile hust-MDT0000 osc hust-mdtlov mdc (obd_config.c:673:class_add_profile()) Add profile hust-MDT0000 Class_add_profile:添加到全局的lustre_profile_list链表 (obd_config.c:788:class_process_config()) processing cmd: cf001 (obd_config.c:167:class_attach()) attach type mds name: hust-MDT0000 uuid: hust-MDT0000_UUID (genops.c:314:class_newdev()) Adding new device hust-MDT0000 (ffff81049cd0a138) (obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (handler.c:1937:mds_setup()) Process entered (handler.c:1966:mds_setup()) hust-MDT0000_UUID: mnt = ffff8104bf412cc0 (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 2 (0x2) hust-MDT0000 add mdt (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 5 (0x1) hust-MDT0000 mdt.group_upcall (obd_config.c:788:class_process_config()) processing cmd: cf00f (obd_config.c:1017:class_process_proc_param()) hust-MDT0000.mdt: set parameter group_upcall=/usr/sbin/l_getgroups (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 5 (0x2) hust-MDT0000 mdt.group_upcall 这和我们上面所说当前hust-MDT0000中记录的日志是一模一样的。 当ost mount的时候lustre_process_log--->obd_process_config--->mgc_process_config---> Mgc_process_log--->class_config_parse_llog---->llog_process分析: Lustre_process_log --lustre_cfg_new(LCFG_LOG_START, &bufs):LCFG_LOG_START命令 --obd_process_config(mgc, sizeof(*lcfg), lcfg) --mgc_process_config(struct obd_device *obd, obd_count len, void *buf) --debug信息:parse_log hust-OST0000 from 0(实际上当我们mount 两个ost 的时候还有一个是parse_log hust-OST0001 from 0) --mgc_process_log(obd, cld) --ctxt = llog_get_context(mgc, LLOG_CONFIG_REPL_CTXT) --mgc_enqueue(mgc->u.cli.cl_mgc_mgsexp, NULL, LDLM_PLAIN, NULL, LCK_CR, &flags, NULL, NULL, NULL, cld, 0, NULL, &lockh) --lctxt = llog_get_context(mgc, LLOG_CONFIG_ORIG_CTXT) --判断是否可以拷贝original llog到replica llog,对于ost来说,根据debug 信息显示确实做了拷贝,调用mgc_copy_llog。 --mgc_copy_llog(mgc, ctxt, lctxt, cld->cld_logname):拷贝远端日志到本地 --llog_create(lctxt, &local_llh, NULL, temp_log) --llog_init_handle(local_llh, LLOG_F_IS_PLAIN, NULL) --llog_destroy(local_llh) --llog_free_handle(local_llh) --llog_create(lctxt, &local_llh, NULL, temp_log) --llog_init_handle(local_llh, LLOG_F_IS_PLAIN, uuid) --llog_create(rctxt, &remote_llh, NULL, logname) --llog_init_handle(remote_llh, LLOG_F_IS_PLAIN, NULL) --llog_process(remote_llh, mgc_copy_handler,(void *)local_llh, NULL) --llog_ctxt_put(ctxt) --ctxt = lctxt:使用local context,也就是使用mgc本地的original context --class_config_parse_llog(ctxt, cld->cld_logname, &cld->cld_cfg) --debug信息:looking up llog hust-OST0000(实际上当mount两个ost 时,还有一个looking up llog hust-OST0001) --llog_create(ctxt, &llh, NULL, name):不同于前面mdt mount的时候 的处理,因为这里使用本地original context,所以这里就不用通过rpc 了,直接使用llog_lvfs_create() --llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL) --llog_process(llh, class_config_llog_handler, cfg, &cd) --llog_process_thread() --llog_next_block() --llog_client_next_block:和llog_create类似,使用本地 的original context的llog_lvfs_next_block() --对于获取的每一个block中的每一条记录执行 lpi->lpi_cb(loghandle, rec,lpi->lpi_cbdata),在此这个函 数就是class_config_llog_handler,对于mdt mount的时 候该函数处理了哪些日志记录,下面展示: --class_process_config Ost mount的时候在class_config_llog_handler中日志处理信息展示: (obd_config.c:1075:class_config_llog_handler()) Marker, inst_flg=0x8 mark_flg=0x1 (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 6 (0x1) hust-OST0000 add ost (obd_config.c:788:class_process_config()) processing cmd: cf001 (obd_config.c:167:class_attach()) attach type obdfilter name: hust-OST0000 uuid: hust-OST0000_UUID (obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (class_hash.c:101:lustre_hash_init()) Process entered (lustre_handles.c:90:class_handle_hash()) Process entered (obd_class.h:873:obd_init_export()) Process entered (ldlm_lockd.c:2051:ldlm_init_export()) Process entered (obd_class.h:403:obd_setup()) Process entered (filter.c:2047:filter_setup()) alloc_pages 'page': 1 page(s) / 4096 bytes at ffff810000c79228. (filter.c:1873:filter_common_setup()) Process entered (obd_mount.c:169:server_get_mount()) Process entered (filter.c:1814:filter_iobuf_pool_init()) Process entered (filter.c:1932:filter_common_setup()) ldiskfs: mnt = ffff810037d03280 (filter.c:1202:filter_prep()) Process entered (filter.c:800:filter_init_server_data()) kmalloced 'fsd': 512 at ffff810021848c00 (filter.c:736:filter_update_server_data()) Process entered (obd_mount.c:71:server_find_mount()) Process entered (filter.c:736:filter_update_server_data()) Process entered (filter.c:738:filter_update_server_data()) server uuid : hust-OST0000_UUID (filter.c:1093:filter_prep_groups()) Process entered (lvfs_linux.c:308:simple_mkdir()) Process entered (filter.c:1097:filter_prep_groups()) got/created O: ffff8100194dfb70 (ldlm_resource.c:324:ldlm_namespace_new()) Process entered (ldlm_lockd.c:2079:ldlm_get_ref()) Process entered (ldlm_pool.c:851:ldlm_pool_init()) Process entered (llog_obd.c:434:obd_llog_init()) Process entered (filter.c:2120:filter_llog_init()) Process entered (recov_thread.c:470:llog_recov_thread_init()) Process entered (ptlrpcd.c:309:ptlrpcd_start()) Process entered (client.c:681:ptlrpc_prep_set()) Process entered (ptlrpcd.c:215:ptlrpcd()) Process entered (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 6 (0x2) hust-OST0000 add ost 那么这些信息时何时被写入到日志文件hust-MDT0000/hust-client的呢?见这里分析: Ost mount的时候记录日志----mgs_write_log_ost lustre_fill_super(struct super_block *sb, void *data, int silent)-----只分析主要逻辑 --server_fill_super(sb):server端mount的时候走这个路径 --server_kernel_mount(sb) --server_start_mgs(sb):这是当我们指定--mgs的时候才会执行,mount ost时不执行 --lustre_start_mgc(sb) --server_start_targets(sb, mnt) --lustre_start_simple(LUSTRE_OSS_OBDNAME,.....) --server_register_target(sb):向mgs注册 --obd_set_info_async(mgc->u.cli.cl_mgc_mgsexp,sizeof(KEY_REGISTER_TAR GET), KEY_REGISTER_TARGET,sizeof(*mti), mti, NULL); --mgc_set_info_async():传递MGS_TARGET_REG命令,mgs_handle中 的处理函数为mgs_handle_target_reg(req),下面我们进入 mgs_handle_target_reg逻辑 --mgs_write_log_target(obd, mti) --mgs_write_log_ost(obd, fsdb, mti):在这里写日志 --record_start_log(obd, &llh, mti->mti_svname) --record_marker,record_attach,record_setup等 --record_end_log(obd, &llh) --name_create(&logname, mti->mti_fsname, \"-MDT0000\") --mgs_write_log_osc(....,logname, fsdb->fsdb_mdtlov,....) --name_create(&oscname, mti->mti_svname, \"-osc\") --record_start_log(obd, &llh, logname) --record_marker,record_attach,record_setup等 --record_lov_add(...,llh, lovname, index, \"1\") --record_end_log(obd, &llh) --name_create(&logname, mti->mti_fsname, \"-client\") --mgs_write_log_osc(....,logname, fsdb->fsdb_clilov,....) --name_create(&oscname, mti->mti_svname, \"-osc\") --record_start_log(obd, &llh, logname) --record_marker,record_attach,record_setup等 --record_lov_add(...,llh, lovname, index, \"1\") --record_end_log(obd, &llh) --lustre_process_log(sb, lsi->lsi_ldd->ldd_svname, &cfg) --server_fill_super_common(sb) 通过以上分析可知,lustre_fill_super是先在server_register_target中写日志记录到日志文件,然后在lustre_process_log中处理日志记录,从而attach/setup设备,或者关联设备(也就是各个设备之间建立关联,比如lov和osc的关联)。 Ost mount的时候处理日志文件----lustre_process_log 在server_register_target--->mgc_set_info_async--->mgs_handle_target_reg 中我们记录日志到日志文件hust-OST0000和hust-client,在lustre_fill_super--->server_fill_super--->server_start_targets--->lustre_process_log中处理的是hust-OST000中的日志记录(至此hust-OST000中记录了ost的记录),如何处理的呢?我们且看: server_start_targets(struct super_block *sb, struct vfsmount *mnt) --lustre_process_log(sb, lsi->lsi_ldd->ldd_svname, &cfg):第二个参数就是logname,这里 是hust-OST0000 --lustre_cfg_new(LCFG_LOG_START, &bufs) --obd_process_config(mgc, sizeof(*lcfg), lcfg) --mgc_process_config:对LCFG_LOG_START命令的处理是mgc_process_log --llog_get_context(mgc, LLOG_CONFIG_REPL_CTXT) --mgc_enqueue(mgc->u.cli.cl_mgc_mgsexp, NULL, LDLM_PLAIN,....) --llog_get_context(mgc, LLOG_CONFIG_ORIG_CTXT) --mgc_copy_llog(mgc, ctxt, lctxt, cld->cld_logname):拷贝日志到本地 --class_config_parse_llog(ctxt, cld->cld_logname, &cld->cld_cfg) --llog_create(ctxt, &llh, NULL, name) --llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL) --llog_process(llh, class_config_llog_handler, cfg, &cd) --llog_process_thread(void *arg) --在此获取以block为单位的日志记录块,然后对于块中的 每一个记录调用class_config_llog_handler分别处理 --class_process_config:真正处理函数,我们看debug 信息: (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 6 (0x1) hust-OST0000 add ost (obd_config.c:788:class_process_config()) processing cmd: cf001 (obd_config.c:167:class_attach()) attach type obdfilter name: hust-OST0000 uuid: hust-OST0000_UUID (filter.c:4118:obdfilter_init()) kmalloced 'obdfilter_created_scratchpad': 4096 at ffff81003636a000. (genops.c:156:class_register_type()) Process entered (genops.c:125:class_get_type()) Loaded module 'obdfilter' (obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_class.h:403:obd_setup()) Process entered (filter.c:2047:filter_setup()) alloc_pages 'page': 1 page(s) / 4096 bytes at ffff810000c79228. (filter.c:1873:filter_common_setup()) Process entered (obd_mount.c:169:server_get_mount()) Process entered (obd_mount.c:71:server_find_mount()) Process entered (filter.c:1814:filter_iobuf_pool_init()) Process entered (filter.c:1202:filter_prep()) Process entered (filter.c:800:filter_init_server_data()) kmalloced 'fsd': 512 at ffff810021848c00. (filter.c:736:filter_update_server_data()) Process entered (lvfs_linux.c:308:simple_mkdir()) Process entered (ldlm_resource.c:324:ldlm_namespace_new()) Process entered (ldlm_lockd.c:2079:ldlm_get_ref()) Process entered (ldlm_pool.c:851:ldlm_pool_init()) Process entered (llog_obd.c:434:obd_llog_init()) Process entered (filter.c:2120:filter_llog_init()) Process entered (llog_obd.c:155:llog_setup()) Process entered (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 6 (0x2) hust-OST0000 add ost 另外我们还将分析这些在server端启动的时候建立的日志,又是如何在client 启动的时候被使用的呢(cleint端mount时关于日志的打印信息见29面,下面仍会摘录关于日志的打印信息,下面的打印信息和29面的基本一致)? 我们知道 Client端lov的配置处理: (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 3 (0x1) hust-clilov lov setup (obd_config.c:788:class_process_config()) processing cmd: cf001 (obd_config.c:167:class_attach()) attach type lov name: hust-clilov-ffff81001cad6400 uuid: 4181fdc6-a186-9fbb-c61d-e0694ea21ef9 (obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (lov_obd.c:841:lov_setup()) Process entered (lov_pool.c:314:lov_ost_pool_init()) Process entered (obd_config.c:352:class_setup()) finished setup of obd hust-clilov-ffff81001cad6400 (uuid 4181fdc6-a186-9fbb-c61d-e0694ea21ef9) (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 3 (0x2) hust-clilov lov setup Client端Mdc的配置处理: (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 4 (0x1) hust-MDT0000 add mdc (obd_config.c:788:class_process_config()) processing cmd: cf005 (obd_config.c:799:class_process_config()) adding mapping from uuid 192.168.2.172@o2ib to nid 0x50000c0a802ac (192.168.2.172@o2ib) (obd_config.c:788:class_process_config()) processing cmd: cf005 (obd_config.c:799:class_process_config()) adding mapping from uuid 192.168.2.172@o2ib to nid 0x20000c0a803ac (192.168.3.172@tcp) (obd_config.c:788:class_process_config()) processing cmd: cf001 (obd_config.c:167:class_attach()) attach type mdc name: hust-MDT0000-mdc-ffff81001cad6400 uuid: 4181fdc6-a186-9fbb-c61d-e0694ea21ef9 (obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (mdc_request.c:1381:mdc_setup()) Process entered (ldlm_lib.c:207:client_obd_setup()) Process entered (ldlm_lockd.c:2079:ldlm_get_ref()) Process entered (llog_obd.c:434:obd_llog_init()) Process entered (mdc_request.c:1524:mdc_llog_init()) Process entered (obd_config.c:352:class_setup()) finished setup of obd hust-MDT0000-mdc-ffff81001cad6400 (uuid 4181fdc6-a186-9fbb-c61d-e0694ea21ef9) (obd_config.c:788:class_process_config()) processing cmd: cf007 (obd_config.c:816:class_process_config()) mountopt: profile hust-client osc hust-clilov mdc hust-MDT0000-mdc (obd_config.c:671:class_add_profile()) Process entered (obd_config.c:673:class_add_profile()) Add profile hust-client (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 4 (0x2) hust-MDT0000 add mdc Hust-OST0000对应的osc在本client的配置处理: (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 8 (0x1) hust-OST0000 add osc (obd_config.c:788:class_process_config()) processing cmd: cf005 (obd_config.c:799:class_process_config()) adding mapping from uuid 192.168.2.169@o2ib to nid 0x50000c0a802a9 (192.168.2.169@o2ib) (obd_config.c:788:class_process_config()) processing cmd: cf005 (obd_config.c:799:class_process_config()) adding mapping from uuid 192.168.2.169@o2ib to nid 0x20000c0a803a9 (192.168.3.169@tcp) (obd_config.c:788:class_process_config()) processing cmd: cf001 (obd_config.c:167:class_attach()) attach type osc name: hust-OST0000-osc-ffff81001cad6400 uuid: 4181fdc6-a186-9fbb-c61d-e0694ea21ef9 (obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (osc_request.c:4385:osc_setup()) Process entered (ldlm_lib.c:207:client_obd_setup()) Process entered (ldlm_lockd.c:2079:ldlm_get_ref()) Process entered (obd_config.c:352:class_setup()) finished setup of obd hust-OST0000-osc-ffff81001cad6400 (uuid 4181fdc6-a186-9fbb-c61d-e0694ea21ef9) (obd_config.c:788:class_process_config()) processing cmd: cf00d (obd_class.h:442:obd_process_config()) Process entered (lov_obd.c:1013:lov_process_config()) Process entered (lov_obd.c:597:lov_add_target()) uuid:hust-OST0000_UUID idx:0 gen:1 active:1 (lov_pool.c:358:lov_ost_pool_add()) Process entered (lov_obd.c:676:lov_add_target()) idx=0 ltd_gen=1 ld_tgt_count=1 (obd_class.h:1517:obd_notify()) Process entered (lov_obd.c:199:lov_notify()) Process entered (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 8 (0x2) hust-OST0000 add osc Hust-OST0001对应的osc在本client的配置处理: (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 11 (0x1) hust-OST0001 add osc (obd_config.c:788:class_process_config()) processing cmd: cf005 (obd_config.c:799:class_process_config()) adding mapping from uuid 192.168.2.169@o2ib to nid 0x50000c0a802a9 (192.168.2.169@o2ib) (obd_config.c:788:class_process_config()) processing cmd: cf005 (obd_config.c:799:class_process_config()) adding mapping from uuid 192.168.2.169@o2ib to nid 0x20000c0a803a9 (192.168.3.169@tcp) (obd_config.c:788:class_process_config()) processing cmd: cf001 (obd_config.c:146:class_attach()) Process entered (obd_config.c:167:class_attach()) attach type osc name: hust-OST0001-osc-ffff81001cad6400 uuid: 4181fdc6-a186-9fbb-c61d-e0694ea21ef9 (obd_config.c:788:class_process_config()) processing cmd: cf003 (obd_config.c:270:class_setup()) Process entered (obd_class.h:403:obd_setup()) Process entered (osc_request.c:4385:osc_setup()) Process entered (obd_config.c:352:class_setup()) finished setup of obd hust-OST0001-osc-ffff81001cad6400 (uuid 4181fdc6-a186-9fbb-c61d-e0694ea21ef9) (obd_config.c:788:class_process_config()) processing cmd: cf00d (obd_class.h:442:obd_process_config()) Process entered (lov_obd.c:1013:lov_process_config()) Process entered (lov_obd.c:597:lov_add_target()) uuid:hust-OST0001_UUID idx:1 gen:1 active:1 (lov_pool.c:358:lov_ost_pool_add()) Process entered (lov_obd.c:676:lov_add_target()) idx=1 ltd_gen=1 ld_tgt_count=2 (obd_class.h:1517:obd_notify()) Process entered (lov_obd.c:199:lov_notify()) Process entered (obd_config.c:788:class_process_config()) processing cmd: cf010 (obd_config.c:857:class_process_config()) marker 11 (0x2) hust-OST0001 add osc 接下来我们将分析client端mount过程中的几个重要的函数(都是对server mount的时候记录在hust-client日志文件中的记录处理的函数),包括: Lov_setup, mdc_setup, osc_setup, lov_add_target lov_setup(struct obd_device *obd, obd_count len, void *buf) --struct lustre_cfg *lcfg = buf --struct lov_obd *lov = &obd->u.lov --struct lov_desc *desc --desc = (struct lov_desc *)lustre_cfg_buf(lcfg, 1):这里的desc是在mgs_write_log_lov中 初始化并计入日志的 --关于lov的初始化 lov->desc = *desc lov_ost_pool_init(&lov->lov_packed, 0) mdc_setup(struct obd_device *obd, obd_count len, void *buf) --struct client_obd *cli = &obd->u.cli --ptlrpcd_addref():确保启动ptlrpcd和ptlrpc-recov --client_obd_setup(obd, len, buf) --struct lustre_cfg* lcfg = buf --struct client_obd *cli = &obddev->u.cli --设置rq_portal,rp_portal,connect_op分别为MDS_REQUEST_PORTAL, MDC_REPLY_PORTAL,MDS_CONNECT --从lustre_cfg中获取server_uuid: memcpy(server_uuid.uuid, lustre_cfg_buf(lcfg, 2), min_t(unsigned int, LUSTRE_CFG_BUFLEN(lcfg, 2), sizeof(server_uuid))):这里server_uuid是在 mgs_write_log_mdt中被赋值并写入日志记录的,下面在client和server建立连接时 需要用到。 --对cli的初始化 --ldlm_get_ref():确保ldlm_setup已经执行 --ptlrpc_init_client(rq_portal, rp_portal, name,&obddev->obd_ldlm_client):根据指定 的rq_portal,rp_portal,name初始化obddev->obd_ldlm_client --imp = class_new_import(obddev) --设置imp的imp_client和imp_connect_op: imp->imp_client = &obddev->obd_ldlm_client imp->imp_connect_op = connect_op --client_import_add_conn(imp, &server_uuid, 1) --import_set_conn(imp, uuid, priority, 1) --根据uuid初始化连接ptlrpc_conn struct ptlrpc_connection * ptlrpc_conn = ptlrpc_uuid_to_connection(uuid) --如果失败则直接返回,否则: --如果指定了create标识,则创建新的imp_conn并且设置imp_conn: imp_conn->oic_conn = ptlrpc_conn; imp_conn->oic_uuid = *uuid; --将imp_conn添加到imp->imp_conn_list链表中 list_add(&imp_conn->oic_item, &imp->imp_conn_list) --设置cli->cli_import:cli->cl_import = imp --obd_llog_init(obd, obd, 0, NULL, NULL) --mdc_llog_init() --llog_setup(obd, LLOG_CONFIG_REPL_CTXT, tgt, 0, NULL, &llog_client_ops) --llog_setup(obd, LLOG_LOVEA_REPL_CTXT, tgt, 0, NULL, &llog_client_ops) osc_setup(struct obd_device *obd, obd_count len, void *buf) --ptlrpcd_addref():确保启动ptlrpcd和ptlrpc-recov --client_obd_setup(obd, len, buf):这里类似于mdc_setup--->client_obd_setup --...... lov_add_target(struct obd_device *obd, struct obd_uuid *uuidp,__u32 index, int gen, int active) --struct lov_obd *lov = &obd->u.lov --struct lov_tgt_desc *tgt --如果满足if ((index < lov->lov_tgt_size) && (lov->lov_tgts[index] != NULL)),则target 已经存在,返回-EEXIST; --如果满足index>= lov->lov_tgt_size---lov->lov_tgt_size表示target array的大小 if (index >= lov->lov_tgt_size) { struct lov_tgt_desc **newtgts newsize = max(lov->lov_tgt_size, (__u32)2) while (newsize < index + 1) newsize = newsize << 1 OBD_ALLOC(newtgts, sizeof(*newtgts) * newsize) memcpy(newtgts, lov->lov_tgts, sizeof(*newtgts) *lov->lov_tgt_size) lov->lov_tgts = newtgts lov->lov_tgt_size = newsize } --OBD_ALLOC_PTR(tgt) --lov_ost_pool_add(&lov->lov_packed, index, lov->lov_tgt_size)//注意这里有lov->lov_packed,前面也看到lov->lov_tgts,这两个结构分别是struct ost_pool和lov_tgt_desc类型,ost_pool中包含一个数组存放着lov管理的target的index,而在lov_obd中定义lov_tgts是struct lov_tgt_desc结构的二维数组struct lov_tgt_desc **lov_tgts,数组中存放的是lov_tgt_desc结构,其中包含target的一些信息。 --lov_ost_pool_extend(op, min_count):如果ost_pool不能容下当前ost则扩大之 --在ost pool中查找指定idx的ost for (i = 0; i < op->op_count; i++) { if (op->op_array[i] == idx) GOTO(out, rc = -EEXIST);//找到则退出 } --op->op_array[op->op_count] = idx//未找到则添加 --op->op_count++;//op->op_count表示ost pool中当前有多少ost,op->op_size则表 示当前ost pool有多大(容量) --初始化tgt tgt->ltd_uuid = *uuidp; tgt->ltd_gen = gen; tgt->ltd_index = index; tgt->ltd_activate = active; lov->lov_tgts[index] = tgt --lov_connect_obd(obd, index, active, &lov->lov_ocd) --struct lov_obd *lov = &obd->u.lov --首先检查log->lov_tgts[index]是否存在,如果不存在则返回-EINVAL --tgt_uuid = lov->lov_tgts[index]->ltd_uuid---获取target对应的uuid --struct obd_device *tgt_obd = class_find_client_obd(&tgt_uuid, LUSTRE_OSC_NAME,&obd->obd_uuid):注意在调用lov_add_target之前我们在 client端已经建立了ost对应的osc结构,如hust-OST0000-osc --确认tgt_obd存在且tgt_obd->obd_set_up==1,否则返回-EINVAL --obd_register_observer(tgt_obd, obd):设置tgt_obd->obd_observer为obd --如果设置了lov->lov_lock_cancel_cb,则调用: obd_register_lock_cancel_cb(tgt_obd, lov->lov_lock_cancel_cb) --如果设置了lov->lov_page_removal_cb则调用: obd_register_page_removal_cb(tgt_obd, lov->lov_page_removal_cb, lov->lov_page_pin_cb) 关于上面的lov_lock_cancel_cb和lov_page_removal_cb作如下说明: 在client_common_fill_super中我们有如下代码: obd = class_name2obd(osc)//这里的obd实际上是lov obd_register_lock_cancel_cb(obd, ll_extent_lock_cancel_cb) obd_register_page_removal_cb(obd, ll_page_removal_cb, ll_pin_extent_cb) 这里实际上调用的是lov_obd_register_lock_cancel_cb和 lov_obd_register_page_removal_cb,所以最终的结果是: lov->lov_lock_cancel_cb = ll_extent_lock_cancel_cb; lov->lov_page_removal_cb = ll_page_removal_cb; lov->lov_page_pin_cb = ll_pin_extent_cb; 而我们这里的tgt_obd则是osc,所以这里分别调用的是: osc_register_lock_cancel_cb和osc_register_page_removal_cb,这里传递的参数 则直接来自于lov,所以注册的三个callback函数也是ll_extent_lock_cancel_cb, ll_page_removal_cb,ll_pin_extent_cb. --和target建立连接: obd_connect(&conn, tgt_obd, &lov_osc_uuid, data, &lov->lov_tgts[index]->ltd_exp) --qos_add_tgt(obd, index):关于qos,在此略过 --lov_notify(obd, tgt->ltd_exp->exp_obd,active ? OBD_NOTIFY_CONNECT : OBD_NOTIFY_INACTIVE,(void *)&index)---lov监视的一定是osc --如果notify的事件是OBD_NOTIFY_ACTIVE || OBD_NOTIFY_INACTIVE if (ev == OBD_NOTIFY_ACTIVE || ev == OBD_NOTIFY_INACTIVE){ if (strcmp(watched->obd_type->typ_name, LUSTRE_OSC_NAME)){ //......如果被监视的对象不是osc,非法,返回 } lov_set_osc_active(obd, &watched->u.cli.cl_target_uuid, ev == OBD_NOTIFY_ACTIVE):设置watched(是osc)为active或 者inactive } --如果tgt->ltd_exp->exp_obd(也就是watched)不为空,则调用 obd_notify_observer(obd, watched, ev, data),将notification向上层传递,也就是传递 给mds?(到底传到哪里,见下面ll_ocd_update分析) --struct obd_notify_upcall *onu = &observer->obd_upcall --onu->onu_upcall(observer, observed, ev, onu->onu_owner):这里的observer就 是lov,observed是osc,事实上纵观整个lustre代码,关于obd_notify_upcall 的地方就只有lov有,在client_common_fill_super中赋值为: obd->obd_upcall.onu_upcall = ll_ocd_update;在ll_ocd_update实现如下: --if (!strcmp(watched->obd_type->typ_name, LUSTRE_OSC_NAME)):如果 watched是osc我们才处理,否则报错 --mdc_init_ea_size(lco->lco_mdc_exp, lco->lco_osc_exp):该函数中的两个 参数都是在client_common_fill_super中初始化的: sbi->ll_lco.lco_mdc_exp = sbi->ll_mdc_exp;//mdc sbi->ll_lco.lco_osc_exp = sbi->ll_osc_exp;//lov 该函数的作用是:对于每一个osc添加事件?初始化默认的和最大的LOV EA和cookie size。 --struct obd_device *obd = mdc_exp->exp_obd --struct client_obd *cli = &obd->u.cli//对应于mdc --struct lov_stripe_md lsm = { .lsm_magic = LOV_MAGIC_V3 } --int rc, size --obd_get_info(lov_exp, sizeof(KEY_LOVDESC), KEY_LOVDESC, &valsize, &desc, NULL):通过lov获取 lov_desc信息 --__u32 stripes stripes = min(desc.ld_tgt_count, (__u32)LOV_MAX_STRIPE_COUNT) --lsm.lsm_stripe_count = stripes --根据lsm信息修正mdc对应的default and maximum LOV EA and cookie sizes,代码如下: lsm.lsm_stripe_count = stripes; size = obd_size_diskmd(lov_exp, &lsm); if (cli->cl_max_mds_easize < size) cli->cl_max_mds_easize = size; lsm.lsm_stripe_count = desc.ld_default_stripe_count; size = obd_size_diskmd(lov_exp, &lsm); if (cli->cl_default_mds_easize < size) cli->cl_default_mds_easize = size; size = stripes * sizeof(struct llog_cookie); if (cli->cl_max_mds_cookiesize < size) cli->cl_max_mds_cookiesize = size; --如果tgt->ltd_exp->exp_obd(也就是watched)为空,则: struct lov_obd *lov = &obd->u.lov struct obd_device *tgt_obd for (i = 0; i < lov->desc.ld_tgt_count; i++) { tgt_obd = class_exp2obd(lov->lov_tgts[i]->ltd_exp) obd_notify_observer(obd, tgt_obd, ev, data) }这里的实现实际上和tgt->ltd_exp->exp_obd(也就是watched)不为空情形下 一样,只不过在指定tgt->ltd_exp->exp_obd(也就是watched)的情况下,只 对该watched调用obd_notify_observer,而没有指定的情况下则对所有的调用 obd_notify_observer 在ll_fill_super中有如下代码: ll_fill_super --lustre_process_log(sb, profilenm, &cfg):处理设备(lov/mdc/osc)的attach/setup --mgc_process_config(struct obd_device *obd, obd_count len, void *buf) --class_config_parse_llog(struct llog_ctxt *ctxt, char *name, struct config_llog_instance *cfg) --当接收到LCFG_LOG_START命令时,执行: mgc_process_log(struct obd_device *mgc,struct config_llog_data *cld) --class_config_parse_llog(struct llog_ctxt *ctxt, char *name, struct config_llog_instance *cfg) 在该函数中会从mgs端获取配置日志信息并根据配置日志对lov, Mdc,osc执行attach和setup等操作,并执行lov_add_target操作, lov_add_target中lov管理的都是osc。 --client_common_fill_super:处理设备之间的连接和注册 --obd = class_name2obd(mdc):mdc --obd_connect(&mdc_conn, obd, &sbi->ll_sb_uuid, data, &sbi->ll_mdc_exp) --client_connect_import(struct lustre_handle *dlm_handle, struct obd_device *obd, struct obd_uuid *cluuid, struct obd_connect_data *data, void *localdata) Client_connect_import返回dlm_handle和sbi->ll_mdc_exp(就是这里的 localdata)这里sbi->ll_mdc_exp实际上是本地创建并初始化的,作为和mds 通讯的接口? --struct client_obd *cli = &obd->u.cli --struct obd_import *imp = cli->cl_import --struct obd_export **exp = localdata --class_connect(dlm_handle, obd, cluuid):返回的dlm_handle中包含export 信息 --struct obd_export *export = class_new_export(obd, cluuid) --OBD_ALLOC(export, sizeof(*export)) --export->exp_obd = obd//这里obd是mdc --class_handle_hash(&export->exp_handle, export_handle_addref) --export->exp_client_uuid = *cluuid//cluuid唯一标识一个client --obd_init_export(export) --conn->cookie = export->exp_handle.h_cookie --*exp = class_conn2export(dlm_handle):从dlm_handle获取export --obd->obd_namespace = ldlm_namespace_new(obd, obd->obd_name, LDLM_NAMESPACE_CLIENT,LDLM_NAMESPACE_GREEDY) 建立mdc的锁名字空间 --imp->imp_dlm_handle = *dlm_handle:初始化mdc对应的ldlm export --ptlrpc_init_import(imp) --ptlrpc_connect_import(imp, NULL) --obd_reconnect:对mdc来说为空 --request = ptlrpc_prep_req(imp, LUSTRE_OBD_VERSION, imp->imp_connect_op,5, size, tmp):准备建立连接rpc请求 --ptlrpcd_add_req(request):将请求交由后台线程处理 --ptlrpc_pinger_add_import(imp) *data = class_exp2cliimp(sbi->ll_mdc_exp)->imp_connect_data:这里我们不关注 data,只关注class_exp2cliimp(sbi->ll_mdc_exp)通过obd_export获取obd_import,方式为struct obd_device *obd = exp->exp_obd;return obd->u.cli.cl_import; --obd = class_name2obd(osc) --obd_connect(&osc_conn, obd, &sbi->ll_sb_uuid, data, &sbi->ll_osc_exp) --lov_connect(struct lustre_handle *conn, struct obd_device *obd, truct obd_uuid *cluuid, struct obd_connect_data *data,void *localdata) Lov_connect返回conn和localdata(实为sbi->ll_osc_exp) --struct lov_obd *lov = &obd->u.lov --struct lov_tgt_desc *tgt; --struct obd_export **exp = localdata; --class_connect(conn, obd, cluuid):这里和前面分析mdc中class_connect-> client_connect_import中class_connect一样,创建export,并通过conn返 回export的信息 --*exp = class_conn2export(conn):通过conn获取obd_export信息 --对lov->lov_tgts数组中的每一个target执行lov_connect_obd,代码: for (i = 0; i < lov->desc.ld_tgt_count; i++) { tgt = lov->lov_tgts[i]; if (!tgt || obd_uuid_empty(&tgt->ltd_uuid)) continue; rc = lov_connect_obd(obd, i, lov->lov_tgts[i]->ltd_activate, &lov->lov_ocd); rc = lov_notify(obd, lov->lov_tgts[i]->ltd_exp->exp_obd, OBD_NOTIFY_CONNECT, (void *)&i); } 实际上在ll_fill_super->lustre_process_log->.....-> lov_add_targert逻辑中已 经调用过lov_connect_obd建立lov和每一个osc的关系,这里再次调用是 否有多余之嫌??? 通过上面对ll_fill_super--->lustre_process_log--->....和ll_fill_super---> client_common_ fill_super--->的分析我们知道:在lustre_process_log中我们完成了lov/mdc/osc的attach和setup,同时完成了lov_add_target(这里建立lov和osc的关联,并且可能对osc执行obd_connect--->client_connect_import和ost建立连接);在client_common_fill_super中则完成了mdc和mds的连接以及osc和ost的连接(通过obd_connect--->lov_connect--->lov_connect_obd--->obd_connect--->client_connect_import),那么我们不禁要问lov和mdc又是如何和client(这里的client是真正的物理实体,不是server在客户端的代理)建立关联的呢?这里我们还是关注clien_common_fill_super: obd = class_name2obd(mdc) obd_connect(&mdc_conn, obd, &sbi->ll_sb_uuid, data, &sbi->ll_mdc_exp) obd = class_name2obd(osc) obd_connect(&osc_conn, obd, &sbi->ll_sb_uuid, data, &sbi->ll_osc_exp) 这两处调用obd_connect分别返回了sbi->ll_mdc_exp和sbi->ll_osc_exp,这两个obd_export实际上就是mds和lov在client端的代理,这样mdc/lov就和client关联了。 以后凡是要和mds交互的地方就使用sbi->ll_mdc_exp,凡是涉及和lov交互的地方就使 用sbi->ll_osc_exp。通常使用这两个obd_export的方式是class_exp2obd(exp),如: 对于sbi->ll_mdc_exp: struct obd_device *obddev = class_exp2obd(exp) struct client_obd *cli = &obddev->u.cli 对于sbi->ll_osc_exp: struct obd_device *obd = class_exp2obd(exp) struct lov_obd *lov = &obd->u.lov 但是我们还有点不明白的地方时lov和mds有何关系?在mds建立的时候也要建立和lov的关系并且注册mds为lov的observer,这里的lov有何用处呢?且看下面分析: mds_setup(struct obd_device *obd, obd_count len, void *buf) -- mds_postsetup(struct obd_device *obd) --llog_setup(obd, LLOG_CONFIG_ORIG_CTXT, obd, 0, NULL,&llog_lvfs_ops) --llog_setup(obd, LLOG_LOVEA_ORIG_CTXT, obd, 0, NULL,&llog_lvfs_ops) --如果mds->mds_profile不为空则执行: if (mds->mds_profile) {:关于mds->mds_profile的说明:在mds_setup中,如果传递的buf(实际上是lustre_cfg类型)对应的lustre_cfg_string(lcfg, 3)存在,则会通过strncpy(mds->mds_profile, lustre_cfg_string(lcfg, 3), LUSTRE_CFG_BUFLEN(lcfg, 3))将其赋值给mds->mds_profile,那么这个lustre_cfg_string(lcfg, 3)是什么呢?下面会分析(紧随“关于mds_lov_connect的分析”之后)。通过分析我们知道这个mds->mds_profile就是mgs_write_log_mdt--->record_setup中的mti->mti_svname,其实就是hust-MDT0000 struct lustre_profile *lprof; lprof = class_get_profile(mds->mds_profile); mds_lov_connect(obd, lprof->lp_osc); } 关于mds_lov_connect的分析: 在mds_postsetup--->mds_lov_connect中传递参数为lprof->lp_osc,实为hust-mdtlov mds_lov_connect(struct obd_device *obd, char * lov_name) --struct mds_obd *mds = &obd->u.mds --struct lustre_handle conn = {0,} --if (mds->mds_osc_obd):如果满足该条件则直接返回0,表示之前已经建立连接 --mds->mds_osc_obd = class_name2obd(lov_name):初始化mds->mds_osc_obd,那么这 个名为hust-mdtlov的设备时何时添加到obd_devs数组中的呢(我们知道class_name2obd 会访问obd_devs数组),答曰:在class_attach中,也就是在处理关于hust-mdtlov的 LCFG_ATTACH的时候会执行class_attach,为hust-mdtlov新创建一个obd_device并添 加到obd_devs数组中。而我们知道在mgs_write_log_mdt中会写关于hust-mdtlov的日 志,该日志会在class_process_config中被处理并调用class_attach和class_setup --mds_lov_read_objids(obd):暂时不关注该函数 --obd_register_observer(mds->mds_osc_obd, obd):注册mds为hust-mdtlov的observer --obd_connect(&conn, mds->mds_osc_obd, &obd->obd_uuid, data, &mds->mds_osc_exp): 这里的mds->mds_osc_obd就是hust-mdtlov,conn和mds->mds_osc_exp是要被返回的, 其中mds->mds_osc_exp作为mds和hust-mdtlov交互的代理。这在client_common_fill_super中已经见识过。这里obd_connect就是lov_connect: lov_connect(struct lustre_handle *conn, struct obd_device *obd, struct obd_uuid *cluuid, struct obd_connect_data *data, void *localdata):这里obd就是hust-mdtlov,cluuid就是mds对应的uuid --struct lov_obd *lov = &obd->u.lov --struct lov_tgt_desc *tgt --struct obd_export **exp = localdata --debug信息:lov->lov_connects = 0,调用lov_connect时lov_connects加一,调用 lov_disconnect时lov_connects减一 --class_connect(conn, obd, cluuid) --export = class_new_export(obd, cluuid) --OBD_ALLOC(export, sizeof(*export)) --export->exp_obd = obd:该export代表的设备??如这里是在为mds准 备hust-mdtlov的export,所以这里export->exp_obd就指向lov,而不是 mds,取而代之的是export->exp_client_uuid是mds的uuid,代表的是mds --class_handle_hash(&export->exp_handle, export_handle_addref) --export->exp_client_uuid = *cluuid --obd_init_export(export) -- --conn->cookie = export->exp_handle.h_cookie --*exp = class_conn2export(conn) --lov->lov_connects++; --对lov->desc.ld_tgt_count个target执行: tgt = lov->lov_tgts[i]; lov_connect_obd(obd, i, lov->lov_tgts[i]->ltd_activate,&lov->lov_ocd) lov_notify(obd, lov->lov_tgts[i]->ltd_exp->exp_obd, OBD_NOTIFY_CONNECT, (void *)&i) 关于hust-mdtlov和hust-clilov: 关于hust-mdtlov在mds端: with only mds mount:---只mount了mds,没有mount ost和client (mgs_llog.c:668:record_base()) lcfg hust-mdtlov 0xcf001 lov hust-mdtlov_UUID (mgs_llog.c:668:record_base()) lcfg (obd_config.c:857:class_process_config()) marker 1 (0x1) hust-mdtlov lov setup (obd_config.c:167:class_attach()) attach type lov name: hust-mdtlov uuid: hust-mdtlov_UUID (genops.c:314:class_newdev()) Adding new device hust-mdtlov (ffff81049c8ca0f8) (obd_config.c:532:class_incref()) incref hust-mdtlov (ffff81049c8ca0f8) now 2 (obd_config.c:532:class_incref()) incref hust-mdtlov (ffff81049c8ca0f8) now 3 (obd_config.c:352:class_setup()) finished setup of obd hust-mdtlov (uuid hust-mdtlov_UUID) (obd_config.c:857:class_process_config()) marker 1 (0x2) hust-mdtlov lov setup (obd_config.c:816:class_process_config()) mountopt: profile hust-MDT0000 osc hust-mdtlov mdc (obd_config.c:532:class_incref()) incref hust-mdtlov (ffff81049c8ca0f8) now 4 with mds mount and 2 ost mount:mds----已经mount,且mount了两个ost (mgs_llog.c:668:record_base()) lcfg hust-OST0000-osc 0xcf001 osc hust-mdtlov_UUID (mgs_llog.c:668:record_base()) lcfg hust-mdtlov 0xcf00d hust-OST0000_UUID 0 1 (obd_config.c:352:class_setup()) finished setup of obd hust-OST0000-osc (uuid hust-mdtlov_UUID) (llog_obd.c:204:llog_setup()) obd hust-mdtlov ctxt 2 is initialized (llog_obd.c:204:llog_setup()) obd hust-mdtlov ctxt 5 is initialized (pinger.c:414:ptlrpc_pinger_add_import()) adding pingable import hust-mdtlov_UUID->hust-OST0000_UUID 在mgs_write_log_osc中我们记录了一条LCFG_LOV_ADD_OBD,在class_process_config中并没有直接处理该命令,而是在default中调用obd_process_config(obd, sizeof(*lcfg), lcfg),而对于LCFG_LOV_ADD_OBD,则调用lov_process_config(事实上对于LCFG_LOV_***都是经过lov_process_config处理)-->lov_add_target--> lov_notify-->obd_notify _observer(lov的observer是mds)-->mds_notify--> mds_lov_start_synchronize-->__mds_lov_synchronize-->mds_lov_update_mds-->mds_lov_update_desc-->llog_cat_initialize-->obd_llog_init-->mds_llog_init-->obd_llog_init-->lov_llog_init-->llog_setup-->osc_llog_init 注意上面的mds_llog_init/lov_llog_init/osc_llog_init中都会调用llog_setup建立日志上下文,且在lov_llog_init中会对lov所管理的所有的target调用osc_llog_init,但是在llog_setup中会首先检测要创建的日志上下文是否存在,如果已经存在则不再创建,所以不会存在重复创建的问题,虽然每次调用lov_add_target后都走同样的路径,但是最终的效果却是除了添加第一个target时会创建mds和lov相关的ctxt外,之后都不在新建mds和lov的ctxt,而是只创建新的target的ctxt(也就是只执行osc_llog_init)。 (mgs_llog.c:668:record_base()) lcfg hust-OST0001-osc 0xcf001 osc hust-mdtlov_UUID (mgs_llog.c:668:record_base()) lcfg hust-mdtlov 0xcf00d hust-OST0001_UUID 1 1 (obd_config.c:352:class_setup()) finished setup of obd hust-OST0001-osc (uuid hust-mdtlov_UUID) (llog_obd.c:177:llog_setup()) obd hust-mdtlov ctxt 2 already set up (llog_obd.c:177:llog_setup()) obd hust-mdtlov ctxt 5 already set up (pinger.c:414:ptlrpc_pinger_add_import()) adding pingable import hust-mdtlov_UUID->hust-OST0001_UUID 关于hust-clilov在mds端: with only mds mount:---只mount了mds,没有mount ost和client (mgs_llog.c:668:record_base()) lcfg hust-clilov 0xcf001 lov hust-clilov_UUID (mgs_llog.c:668:record_base()) lcfg with mds mount and 2 ost mount:mds----已经mount,且mount了两个ost (mgs_llog.c:668:record_base()) lcfg hust-OST0000-osc 0xcf001 osc hust-clilov_UUID (mgs_llog.c:668:record_base()) lcfg hust-clilov 0xcf00d hust-OST0000_UUID 0 1 (mgs_llog.c:668:record_base()) lcfg hust-OST0001-osc 0xcf001 osc hust-clilov_UUID (mgs_llog.c:668:record_base()) lcfg hust-clilov 0xcf00d hust-OST0001_UUID 1 1 关于hust-clilov在client端: (obd_config.c:857:class_process_config()) marker 3 (0x1) hust-clilov lov setup (obd_config.c:1152:class_config_llog_handler()) cmd cf001, instance name: hust-clilov-ffff81003ddbcc00 (obd_config.c:167:class_attach()) attach type lov name: hust-clilov-ffff81003ddbcc00 uuid: 45725052-8571-9636-a7e8-7a0629fa2eab (genops.c:314:class_newdev()) Adding new device hust-clilov-ffff81003ddbcc00 (ffff81001a97a338) (obd_config.c:1152:class_config_llog_handler()) cmd cf003, instance name: hust-clilov-ffff81003ddbcc00 (obd_config.c:532:class_incref()) incref hust-clilov-ffff81003ddbcc00 (ffff81001a97a338) now 2 (obd_config.c:532:class_incref()) incref hust-clilov-ffff81003ddbcc00 (ffff81001a97a338) now 3 (obd_config.c:352:class_setup()) finished setup of obd hust-clilov-ffff81003ddbcc00 (uuid 45725052-8571-9636-a7e8-7a0629fa2eab) (obd_config.c:857:class_process_config()) marker 3 (0x2) hust-clilov lov setup (obd_config.c:816:class_process_config()) mountopt: profile hust-client osc hust-clilov mdc hust-MDT0000-mdc (obd_config.c:1152:class_config_llog_handler()) cmd cf00d, instance name: hust-clilov-ffff81003ddbcc00 (obd_config.c:1152:class_config_llog_handler()) cmd cf00d, instance name: hust-clilov-ffff81003ddbcc00 (llite_lib.c:1212:ll_fill_super()) Found profile hust-client: mdc=hust-MDT0000-mdc osc=hust-clilov (obd_config.c:532:class_incref()) incref hust-clilov-ffff81003ddbcc00 (ffff81001a97a338) now 4 这里是在client端将hust-OST0000-osc和hust-OST0001-osc添加到hust-clilov管理之中。调用关系:class_config_llog_handler-->class_process_config-->obd_process_config-->lov_process _config-->lov_add_target-->lov_notify就返回了。。。为什么lov_notify就返回呢? 从上面分析我们知道hust-mdtlov和hust-clilov中都有关于target的信息。 关于mds->mds_profile的值的分析: server_start_targets(struct super_block *sb, struct vfsmount *mnt) --lustre_start_simple(LUSTRE_MDS_OBDNAME,...)//会调用mdt_attach和mdt_setup --server_register_target(sb):mdt向mgs注册 --obd_set_info_async(mgc->u.cli.cl_mgc_mgsexp,... KEY_REGISTER_TARGET,....):会向mgs发送MGS_TARGET_REG 命令,mgs端处理函数为mgs_handle,mgs_handle处理如下: --mgs_handle_target_reg(req):针对MGS_TARGET_REG命令 --mgs_write_log_target(obd, mti) --mgs_write_log_mdt(obd, fsdb, mti) --mgs_write_log_lov(obd, fsdb, mti, mti->mti_svname, fsdb->fsdb_mdtlov) --record_start_log(obd, &llh, mti->mti_svname):llh关联的日志文 件名为hust-MDT0000 --record_marker(obd, llh, fsdb, CM_START, mti->mti_svname,\"add mdt\") --record_mount_opt(obd, llh, mti->mti_svname, fsdb->fsdb_mdtlov, 0) --record_base(obd,llh,NULL,0,LCFG_MOUNTOPT, profile,lov_name,mdc_name,0) ----struct lustre_cfg_bufs bufs --struct lustre_cfg *lcfg --lustre_cfg_bufs_reset(&bufs, cfgname) --lustre_cfg_bufs_set_string(&bufs, 1, s1) --lustre_cfg_bufs_set_string(&bufs, 2, s2) --lustre_cfg_bufs_set_string(&bufs, 3, s3) --lustre_cfg_bufs_set_string(&bufs, 4, s4) --lcfg = lustre_cfg_new(cmd, &bufs) --record_lcfg(obd, llh, lcfg) --record_attach(obd, llh, mti->mti_svname, LUSTRE_MDS_NAME, mti->mti_uuid) --record_setup(obd, llh, mti->mti_svname, mti->mti_uuid,\"0\" ,mti->mti_svname,0 ) --record_base(obd,llh,devname,0,LCFG_SETUP,s1,s2,s3,s4): --struct lustre_cfg_bufs bufs --struct lustre_cfg *lcfg --lustre_cfg_bufs_reset(&bufs, cfgname) --lustre_cfg_bufs_set_string(&bufs, 1, s1) --lustre_cfg_bufs_set_string(&bufs, 2, s2) --lustre_cfg_bufs_set_string(&bufs, 3, s3) --lustre_cfg_bufs_set_string(&bufs, 4, s4) --lcfg = lustre_cfg_new(cmd, &bufs) --record_lcfg(obd, llh, lcfg) --record_marker(obd, llh, fsdb, CM_END, mti->mti_svname, \"add mdt\") --record_end_log(obd, &llh) --name_create(&cliname, mti->mti_fsname, \"-client\"):hust-client --name_create(&mdcname, mti->mti_svname, \"-mdc\"): hust-MDT 000-mdc --record_start_log(obd, &llh, cliname):llh关联的日志文 件名为 hust-client --record_marker(obd, llh, fsdb, CM_START, mti->mti_svname,\"add mdc\") --record_add_uuid(obd, llh, mti->mti_nids[i],nodeuuid) --record_attach(obd, llh, mdcname, LUSTRE_MDC_NAME, mdcuuid) --record_setup(obd, llh, mdcname, mti->mti_uuid,nodeuuid,0, 0) --mgs_write_log_failnids(obd, mti, llh, mdcname) --record_mount_opt(obd, llh, cliname, fsdb->fsdb_clilov,mdcname) --record_marker(obd, llh, fsdb, CM_END, mti->mti_svname, \"add mdc\") -- record_end_log(obd, &llh) --lustre_process_log(sb, lsi->lsi_ldd->ldd_svname, &cfg)//第二个参数就是日志文件名 --obd_process_config(mgc, sizeof(*lcfg), lcfg) --声明和初始化 struct lustre_cfg *lcfg; struct lustre_cfg_bufs bufs; struct lustre_sb_info *lsi = s2lsi(sb); struct obd_device *mgc = lsi->lsi_mgc; --根据sb,日志文件名,cfg初始化bufs lustre_cfg_bufs_reset(&bufs, mgc->obd_name); lustre_cfg_bufs_set_string(&bufs, 1, logname); lustre_cfg_bufs_set(&bufs, 2, cfg, sizeof(*cfg)); lustre_cfg_bufs_set(&bufs, 3, &sb, sizeof(sb)); --根据bufs生成lcfg lcfg = lustre_cfg_new(LCFG_LOG_START, &bufs) --obd_process_config(mgc, sizeof(*lcfg), lcfg):处理lcfg --对于LCFG_LOG_START命令: --解析出logname,cfg,sb char *logname = lustre_cfg_string(lcfg, 1); cfg = (struct config_llog_instance *)lustre_cfg_buf(lcfg, 2); sb = *(struct super_block **)lustre_cfg_buf(lcfg, 3); --将这个日志添加到活动的配置日志链表中 config_log_add(logname, cfg, sb):实际上是通过参数先生成struct config_llog_data,然后将struct config_llog_data结构挂在 config_llog_list中 --返回该logname对应的struct config_llog_data结构 cld = config_log_find(logname, cfg): --mgc_process_log(obd, cld) --class_config_parse_llog(ctxt, cld->cld_logname, &cld->cld_cfg) --class_config_llog_handler(struct llog_handle * handle, struct llog_rec_hdr *rec, void *data) --char *cfg_buf = (char*) (rec + 1) --struct lustre_cfg *lcfg = (struct lustre_cfg *)cfg_buf --lustre_cfg_bufs_init(&bufs, lcfg) --struct lustre_cfg *lcfg_new = lustre_cfg_new (lcfg->lcfg_command, &bufs):根据旧的lcfg生成新的 lcfg_new --class_process_config(lcfg_new):处理新的lcfg_new --对各种命令处理: case LCFG_MOUNTOPT: { CDEBUG(D_IOCTL, \"mountopt: profile %s osc %s mdc %s\\n\1),//profilename:hust-MDT0000 lustre_cfg_string(lcfg, 2),//lov_name:hust-mdtlov lustre_cfg_string(lcfg, 3));//mdc_name:NULL err= class_add_profile(LUSTRE_CFG_BUFLEN (lcfg, 1),lustre_cfg_string(lcfg, 1), LUSTRE_CFG_BUFLEN(lcfg, 2), lustre_cfg_string(lcfg, 2), LUSTRE_CFG_BUFLEN(lcfg, 3), lustre_cfg_string(lcfg, 3)); } case LCFG_DETACH: { err = class_detach(obd, lcfg); GOTO(out, err = 0); } case LCFG_SETUP: {//0414 err = class_setup(obd, lcfg); GOTO(out, err); } 终于到了class_setup了,对于mds来说就是mds_setup,关于mds_setup的分析见“关于mds->mds_profile的值的分析”前面一节。 关于lustre_profile: (1)在mgs_write_log_mdt中调用record_mount_opt添加(profilename,lov_name,mdc_name) =(hust-MDT0000,hust-mdtlov,NULL)三元组到日志文件hust-MDT0000中; 在class_process_config中根据日志记录构成lustre_profile结构并调用class_add_profile 添加到全局的lustre_profile_list链表中; 在mds_postsetup中调用Class_get_profile通过profile名称(mds->mds_profile,即 hust-MDT0000)到全局的lustre_profile_list链表中查找获取相应的lustre_profile信息; (2)在mgs_write_log_mdt中调用record_mount_opt添加(profilename,lov_name,mdc_name) =(hust-client,hust-clilov,hust-MDT0000-mdc) 三元组到日志文件hust-client中; 在class_process_config中根据日志记录构成lustre_profile结构并调用class_add_profile 添加到全局的lustre_profile_list链表中; 在ll_fill_super中调用Class_get_profile通过profile名称(s2lsi(sb)->lsi_lmd->lmd_profile, 即hust-client)到全局的lustre_profile_list链表中查找获取相应的lustre_profile信息; 关于mds和hust-mdtlov之间的关系: 在struct mds_obd{ struct obd_device *mds_osc_obd; /* XXX lov_obd */ struct obd_uuid mds_lov_uuid; struct obd_export *mds_osc_exp; /* XXX lov_exp */ struct lov_desc mds_lov_desc; }这几个域都与lov相关,我们着重看mds_osc_obd和mds_osc_exp,mds_lov_desc。 关于mds_osc_obd: Mds_postsetup --mds_lov_connect --mds->mds_osc_obd = class_name2obd(lov_name) --obd_register_observer(mds->mds_osc_obd, obd):注册mds作为hust-mdtlov的 observer 在这里通过mds_osc_obd建立mds和hust-mdtlov的关联,以后要使用hust-mdtlov的话就通过下面的形式: struct obd_device *lov_obd = obd->u.mds.mds_osc_obd 关于mds_osc_exp: Mds_postsetup --mds_lov_connect --mds->mds_osc_obd = class_name2obd(lov_name) --obd_connect(&conn, mds->mds_osc_obd, &obd->obd_uuid, data, &mds->mds_osc_exp):关联mds和lov,返回mds->mds_osc_exp,作为lov在mds 端的代理 使用mds->mds_osc_exp的地方主要有以下函数: obd_alloc_memmd/obd_free_memmd,obd_packmd/obd_unpackmd,obd_connect/ obd_disc onnect ,obd_create/obd_destroy,dqacq_adjust_qunit_sz(关于quota,不讲解)下面逐一分析。 obd_alloc_memmd/obd_free_memmd: mds_log_lost_precreated --obd_alloc_memmd(obd->u.mds.mds_osc_exp, &lsm) --obd_unpackmd(exp, mem_tgt, NULL, 0) --OBP(exp->exp_obd, unpackmd)(exp, mem_tgt, disk_src, disk_len):从mds_lov_connect-->lov_connect-->class_connect,我们知道mds_osc_exp就是对应于lov,mds->mds_osc_exp->exp_obd就是lov,所以这里调用lov_unpackmd mds_create_objects --obd_free_memmd(mds->mds_osc_exp, &oinfo.oi_md) --obd_unpackmd(exp, mem_tgt, NULL, 0) --OBP(exp->exp_obd, unpackmd)(exp, mem_tgt, disk_src, disk_len):从 mds_lov_connect-->lov_connect-->class_connect,我们知道mds_osc_exp就是对 应于lov,mds->mds_osc_exp->exp_obd就是lov,所以这里调用lov_unpackmd lov_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp, struct lov_mds_md *lmm, int lmm_bytes):该函数被obd_alloc_memmd和obd_free_memmd公用,但是如果是alloc,则*lsmp == NULL,否则*lsmp != NULL,关于该函数的理解:lov_stripe_md和lov_mds_md的理解参考http://wiki.lustre.org/index.php/ Architecture_-_MDS_striping_format,其实 lov_mds_md:In-disk format,used when the striping EA is stored in disk Lov_stripe_md:in-memory format,used when the striping EA is being read out from the disk and unpacked --struct obd_device *obd = class_exp2obd(exp) --lov_obd *lov = &obd->u.lov --stripe_count = lov_get_stripecnt(lov, 0) --If we are passed an allocated struct but nothing to unpack, free if (*lsmp && !lmm) { lov_free_memmd(lsmp); RETURN(0); } --lsm_size = lov_alloc_memmd(lsmp, stripe_count, LOV_PATTERN_RAID0,magic) --If we are passed a pointer but nothing to unpack, we only alloc,lmm为空,没什么unpack if (!lmm) RETURN(lsm_size); --lsm_op_find(magic)->lsm_unpackmd(lov, *lsmp, lmm):该函数用lmm填充*lsmp 关于obd_packmd/obd_unpackmd: mds_convert_lov_ea(struct obd_device *obd, struct inode *inode, struct lov_mds_md *lmm, int lmm_size, __u64 connect_flags) --obd_unpackmd(obd->u.mds.mds_osc_exp, &lsm, lmm, lmm_size):Unpack an MD struct from disk to in-memory format,这里对应lov_unpackmd前面已经讲解 --obd_packmd(obd->u.mds.mds_osc_exp, &lmm, lsm):Pack an in-memory MD struct for storage on disk,这里对应lov_packmd:Pack LOV object metadata for disk storage,比较 简单 关于Obd_connect/obd_disconnect: mds_lov_connect(struct obd_device *obd, char * lov_name) --obd_connect(&conn, mds->mds_osc_obd, &obd->obd_uuid, data, &mds->mds_osc_exp): 建立hust-mdtlov和mds关联,并且返回mds->mds_osc_exp,在讲mds_lov_connect处 已经讲解 mds_lov_clean(struct obd_device *obd) --obd_disconnect(mds->mds_osc_exp) --对lov->lov_tgts中所有元素执行: lov_del_target(obd, i, 0, lov->lov_tgts[i]->ltd_gen) 关于mds_lov_desc: mds_lov_update_desc(struct obd_device *obd, __u32 index,struct obd_uuid *uuid) --struct mds_obd *mds = &obd->u.mds --struct lov_desc *ld --__u32 valsize = sizeof(mds->mds_lov_desc) --OBD_ALLOC(ld, sizeof(*ld)):分配lov_desc --obd_get_info(mds->mds_osc_exp, sizeof(KEY_LOVDESC), KEY_LOVDESC, &valsize, ld, NULL):这里返回ld --lov_get_info(struct obd_export *exp, __u32 keylen, void *key, __u32 *vallen, void *val,struct lov_stripe_md *lsm):key是KEY_LOVDESC,处理如下: --struct obd_device *obddev = class_exp2obd(exp) --struct lov_obd *lov = &obddev->u.lov --struct lov_desc *desc_ret = val --*desc_ret = lov->desc:也就是将lov->desc直接给val --mds->mds_lov_desc = *ld mds_lov_update_mds(struct obd_device *obd,struct obd_device *watched,__u32 idx):Inform MDS about new/updated target,当有新添加的target或者更新的target时通知mds --struct mds_obd *mds = &obd->u.mds --old_count = mds->mds_lov_desc.ld_tgt_count --mds_lov_update_desc(obd, idx, &watched->u.cli.cl_target_uuid):前面已讲 --mds_lov_get_objid(obd, idx) --obd_get_info(mds->mds_osc_exp, sizeof(KEY_LAST_ID), KEY_LAST_ID, &size, &lastid, NULL) --lov_get_info(struct obd_export *exp, __u32 keylen,void *key, __u32 *vallen, void *val,struct lov_stripe_md *lsm):此处传递的key 是KEY_LAST_ID,用于 --struct obd_id_info *info = val --struct lov_tgt_desc *tgt = lov->lov_tgts[info->idx] --obd_get_info(tgt->ltd_exp, keylen, key, &size, info->data, NULL):根据 lov_connect_obd-->obd_connect(&conn, tgt_obd, &lov_osc_uuid, data, &lov->lov_tgts[index]->ltd_exp)中我们知道lov->lov_tgts[index]->ltd_exp 就是osc在lov端的代理,所以这里调用osc_get_info这里osc(这里osc 在mds端,记住hust-mdtlov中管理着hust-OST0000-osc等)向相应的ost发送请求,获取KEY_LAST_ID,请求的opcode是OST_GET_INFO,所以从这里我们也可以知道为什么要有hust-mdtlov,为什么mds和ost之间要通信: --ptlrpc_prep_req(class_exp2cliimp(exp), LUSTRE_OST_VERSION, OST_GET_INFO, 2, size, bufs):关于这里的 class_exp2cliimp(exp),我们知道这里的exp是osc在lov处的代理,所 以通过该exp可以获取相应的obd,然后通过obd获取import,代码 为: struct obd_device *obd = exp->exp_obd return obd->u.cli.cl_import --ptlrpc_queue_wait(req) --ptlrpc_req_finished(req) 关于mgs_handle_target_reg: mgs_handle_target_reg(struct ptlrpc_request *req) --mgs_write_log_target(obd, mti) --mgs_find_or_make_fsdb(obd, mti->mti_fsname, &fsdb) --mgs_new_fsdb(obd, name) --name_create(&fsdb->fsdb_mdtlov, fsname, \"-mdtlov\"):hust-mdtlov --name_create(&fsdb->fsdb_clilov, fsname, \"-clilov\"):hust-clilov --mgs_write_log_mdt(obd, fsdb, mti)/mgs_write_log_ost(obd, fsdb, mti):分别针对是 mdt还是ost执行,后面讲解mgs_write_log_mdt/mgs_write_log_ost --mgs_write_log_params(obd, fsdb, mti) //在hust-MDT0000中记录日志关于hust-mdtlov和hust-MDT0000的日志 //在hust-client中记录关于hust-MDT0000-mdc和hust-clilov的日志 mgs_write_log_mdt(struct obd_device *obd, struct fs_db *fsdb,struct mgs_target_info *mti) --CDEBUG打印信息:writing new mdt hust-MDT0000 --mgs_write_log_lov(obd, fsdb, mti, mti->mti_svname,fsdb->fsdb_mdtlov):这里的lovname 是hust-mdtlov,llogname是hust-MDT0000 --CDEBUG打印信息:Writing log hust-MDT0000(hust-MDT0000是logname) --OBD_ALLOC(lovdesc, sizeof(*lovdesc)) --初始化lovdesc --record_start_log(obd, &llh, logname) --ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT) --llog_create(ctxt, llh, NULL, name) --llog_init_handle(*llh, LLOG_F_IS_PLAIN, &cfg_uuid) --record_marker(obd, llh, fsdb, CM_START, lovname, \"lov setup\"):配置记录开始 --record_attach(obd, llh, lovname, \"lov\:传递LCFG_ATTACH命令 --record_lov_setup(obd, llh, lovname, lovdesc):传递LCFG_SETUP命令 --record_marker(obd, llh, fsdb, CM_END, lovname, \"lov setup\"):配置记录结束 --record_end_log(obd, &llh):和record_start_log对应 --llog_close(*llh) --OBD_FREE(lovdesc, sizeof(*lovdesc)) --record_start_log(obd, &llh, mti->mti_svname):日志文件名称为hust-MDT0000 --record_marker(obd, llh, fsdb, CM_START, mti->mti_svname,\"add mdt\") --record_mount_opt(obd, llh, mti->mti_svname, fsdb->fsdb_mdtlov, 0):fsdb->fsdb_mdtlov是hust-mdtlov,LCFG_MOUNTOPT命令 --record_attach(obd, llh, mti->mti_svname, LUSTRE_MDS_NAME,mti->mti_uuid) --record_setup(obd, llh, mti->mti_svname,mti->mti_uuid ,\"0\",mti->mti_svname,0) --record_marker(obd, llh, fsdb, CM_END, mti->mti_svname, \"add mdt\") --record_end_log(obd, &llh) --name_create(&cliname, mti->mti_fsname, \"-client\"):cliname是hust-client --mgs_write_log_lov(obd, fsdb, mti, cliname,fsdb->fsdb_clilov):这里的llog_name是hust-client,fsdb->fsdb_clilov是hust-clilov,实现前面已分析 --name_create(&nodeuuid, libcfs_nid2str(mti->mti_nids[0]),/*\"_UUID\"*/\"\") --name_create(&mdcname, mti->mti_svname, \"-mdc\"):mdcname将是hust-MDT0000-mdc --name_create(&mdcuuid, mdcname, \"_UUID\"):mdcuuid是hust-MDT0000-mdc_UUID --record_start_log(obd, &llh, cliname):cliname为hust-client --record_marker(obd, llh, fsdb, CM_START, mti->mti_svname,\"add mdc\") --对mount_target_info中的所有nid执行record_add_uuid for (i = 0; i < mti->mti_nid_count; i++) { rc = record_add_uuid(obd, llh, mti->mti_nids[i],nodeuuid); } --record_attach(obd, llh, mdcname, LUSTRE_MDC_NAME, mdcuuid) --record_setup(obd, llh, mdcname, mti->mti_uuid,nodeuuid,0, 0) --mgs_write_log_failnids(obd, mti, llh, mdcname) --record_mount_opt(obd, llh, cliname, fsdb->fsdb_clilov,mdcname) --record_marker(obd, llh, fsdb, CM_END, mti->mti_svname, \"add mdc\") --record_end_log(obd, &llh) mgs_write_log_ost(struct obd_device *obd, struct fs_db *fsdb,struct mgs_target_info *mti) --CDEBUG信息:writing new ost hust-OST0000(事实上在我们mount两个ost的时候 还有一个打印信息是writing new ost hust-OST0001,但是这里我们只讲一个) --record_start_log(obd, &llh, mti->mti_svname):mti->mti_svname也就是llog_name是 hust-OST0000,这里打开该文件,返回llog_handle --record_marker(obd, llh, fsdb, CM_START, mti->mti_svname,\"add ost\") --record_attach(obd, llh, mti->mti_svname,\"obdfilter\",mti->mti_uuid) --record_setup(obd, llh, mti->mti_svname,\"dev\--record_marker(obd, llh, fsdb, CM_END, mti->mti_svname, \"add ost\") --record_end_log(obd, &llh) --name_create(&logname, mti->mti_fsname, \"-MDT0000\"):logname将是hust-MDT0000 --mgs_write_log_osc(obd, fsdb, mti, logname, fsdb->fsdb_mdtlov,flags):fsdb->fsdb_mdtlov 是hust-mdtlov --如果日志文件hust-MDT0000是空的,则执行: if (mgs_log_is_empty(obd, logname)) { /* The first item in the log must be the lov, so we have somewhere to add our osc. */ rc = mgs_write_log_lov(obd, fsdb, mti, logname, lovname); } --name_create(&oscname, mti->mti_svname, \"-osc\"):oscname将是hust-OST0000-osc --name_create(&oscuuid, oscname, \"_UUID\")’ --name_create(&lovuuid, lovname, \"_UUID\") --record_start_log(obd, &llh, logname) --record_marker(obd, llh, fsdb, CM_START | flags, mti->mti_svname,\"add osc\") --对mgs_target_info中所有的nid执行add_nid: for (i = 0; i < mti->mti_nid_count; i++) { rc = record_add_uuid(obd, llh, mti->mti_nids[i], nodeuuid); } --record_attach(obd, llh, oscname, LUSTRE_OSC_NAME, lovuuid) --record_setup(obd, llh, oscname, mti->mti_uuid, nodeuuid, 0, 0) --mgs_write_log_failnids(obd, mti, llh, oscname) --record_lov_add(obd, llh, lovname, mti->mti_uuid, index, \"1\") --record_base(obd,llh,lov_name,0,LCFG_LOV_ADD_OBD,ost_uuid,index,gen,0) :LCFG_LOV_ADD_OBD命令,向日志中写向lov中添加ost记录 --record_marker(obd, llh, fsdb, CM_END | flags, mti->mti_svname,\"add osc\") --record_end_log(obd, &llh) --name_destroy(&logname) --name_create(&logname, mti->mti_fsname, \"-client\") --mgs_write_log_osc(obd, fsdb, mti, logname, fsdb->fsdb_clilov,flags):fsdb->fsdb_clilov是hust-clilov --name_destroy(&logname) Lustre_fill_super--->client_fill_super--->ll_fill_super--->client_common_fill_super--->obd_connect--->client_connect_import实现分析: client_connect_import(struct lustre_handle *dlm_handle, struct obd_device *obd, struct obd_uuid *cluuid, struct obd_connect_data *data, void *localdata) --class_connect(dlm_handle, obd, cluuid) --export = class_new_export(obd, cluuid) --conn->cookie = export->exp_handle.h_cookie:这里的conn对应于dlm_handle --obd->obd_namespace=ldlm_namespace_new(obd,obd->obd_name,LDLM_NAMESPACE _CLIENT , LDLM_NAMESPACE_GREEDY) --ptlrpc_init_import(imp) --ptlrpc_connect_import(imp, NULL):在这里发送connect命令道server端,这里发送的 命令的操作码是MGS_CONNECT,到达mgs端的处理则为 (2)我们剥离出与lov相关的代码,如下: Mds_setup --mds_postsetup --如果mds->mds_profile不为空,则执行: lprof = class_get_profile(mds->mds_profile) mds_lov_connect(obd, lprof->lp_osc) --mds->mds_osc_obd = class_name2obd(lov_name):如果没找到,则说明lov尚 未建立,出错返回 --obd_register_observer(mds->mds_osc_obd, obd):注册mds为lov的observer --obd_connect(&conn, mds->mds_osc_obd, &obd->obd_uuid, data, &mds->mds_osc_exp) --lov_connect 那么上面的逻辑中mds->mds_profile又是如何初始化的呢?如果 class_name2obd(lov_name)能找到lov,那么lov又是在哪里被建立的呢? 在mds_setup中如果满足if (lcfg->lcfg_bufcount >= 4 && LUSTRE_CFG_BUFLEN(lcfg, 3) > 0) ,则会调用strncpy(mds->mds_profile, lustre_cfg_string(lcfg, 3),LUSTRE_CFG_BUFLEN(lcfg, 3))对mds->mds_profile进行赋值。 Lov是在哪里被建立的呢? 根据mds端debug信息显示,setup的顺序为mgs_setup,mgc_setup,mdt_setup,mgs_write_log_target, mgs_write_log_mdt, mgs_write_log_lov, mgs_write_log_params, mgs_write_log_direct, lov_setup, mds_setup(这里mdt_setup和mds_setup感觉有点颠倒,因为代码是在mdt_setup中建立服务的),明天继续分析!!!! Mgs_write_log_target(struct obd_device *obd,struct mgs_target_info *mti) --mgs_set_index(obd, mti) --mgs_find_or_make_fsdb(obd, mti->mti_fsname, &fsdb):这里的mti->mti_fsname就 是我们在mkfs.lustre的时候指定的--fsname=***中的***。 --mgs_find_fsdb(obd, name)这里的name就是前面的mti->mti_fsname,该函数 遍历mgs的mgs->mgs_fs_db_list链表,查找指定name的fsdb。 --如果找到则返回,没有找到则调用mgs_new_fsdb(obd, name)创建一个,并添 加到mgs->mgs_fs_db_list中。Mgs_new_fsdb函数分析见下面。 --mgs_get_fsdb_from_llog(struct obd_device *obd, struct fs_db *fsdb),该函数分 析见下面 --mgs_find_or_make_fsdb(obd, mti->mti_fsname, &fsdb):再次调用 mgs_find_or_make_fsdb,这次调用肯定是在mgs_find_fsdb中就返回,因为我们确信已 经有了(在mgs_set_index中创建的)。 --根据mti->mti_flags是mdt还是ost决定调用mgs_write_log_mdt或者mgs_write_log_ost --mgs_write_log_params(obd, fsdb, mti):根据debug信息显示暂时可以不关注。 mgs_new_fsdb(struct obd_device *obd, char *fsname) --OBD_ALLOC_PTR(fsdb) 分配fsdb结构 --为ost和mdt分配使用过的index bitmap OBD_ALLOC(fsdb->fsdb_ost_index_map, INDEX_MAP_SIZE); OBD_ALLOC(fsdb->fsdb_mdt_index_map, INDEX_MAP_SIZE); --strncpy(fsdb->fsdb_name, fsname, sizeof(fsdb->fsdb_name)) 初始化fsbd::fsdb_name --name_create(&fsdb->fsdb_mdtlov, fsname, \"-mdtlov\"):组合faname和mdtlov --name_create(&fsdb->fsdb_clilov, fsname, \"-clilov\"):组合faname和clilov --上面的组合结果就是我们在debug信息中看到的hust-mdtlov,hust-clilov等 --list_add(&fsdb->fsdb_list, &mgs->mgs_fs_db_list):添加到mgs->mgs_fsdb_list链表 Mgs_get_fsdb_from_llog(struct obd_device *obd, struct fs_db *fsdb) --ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT) --name_create(&logname, fsdb->fsdb_name, \"-client\"):生成logname为hust-client --llog_create(ctxt, &loghandle, NULL, logname) --对应于llog_lvfs_create,而且此时在llog_create中指定了logname所以在 llog_lvfs_create中,将执行: --handle = llog_alloc_handle(): 分配llog_handle --handle->lgh_file = llog_filp_open(MOUNT_CONFIGS_DIR,name, open_flags, 0644); --llog_init_handle(loghandle, LLOG_F_IS_PLAIN, NULL) --llog_process(loghandle, mgs_fsdb_handler, (void *)fsdb, NULL):在mgs和mdt正常启动 过程中并没有调用到mgs_fsdb_handler,可能是loghandle中没有有效日志的缘故吧 --llog_close(loghandle) --llog_put_ctxt 下面分析一下mgs_write_log_mdt: mgs_write_log_mdt(struct obd_device *obd, struct fs_db *fsdb,struct mgs_target_info *mti) --如果mgs_log_is_empty(obd, mti->mti_svname)则调用mgs_write_log_lov(注释 “Append mdt info to mdt log”)代码: if (mgs_log_is_empty(obd, mti->mti_svname)) { first_log++; rc = mgs_write_log_lov(obd, fsdb, mti, mti->mti_svname, fsdb->fsdb_mdtlov);下面分析,这里传递的第四五个参数分别为mti->mti_svname和fsdb->fsdb_mdtlov,分别为hust-mdt0000和hust-mdtlov,所以操作的日志文件为hust-mdt0000,hust-mdtlov作为config device name传递给lustre_cfg(通过lustre_cfg_bufs_reset),最后被用于处理日志记录时寻找相应的设备(所以说这个config device name肯定是和obd->obd_name一样的) } --record_start_log(obd, &llh, mti->mti_svname):这里的第三个参数和mgs_write_log_lov 中的第四个参数一样,而在mgs_write_log_lov中调用record_start_log的时候传递的第 三个参数也是mti->mti_svname(hust-MDT0000),这是因为record_start_log就是打开 以mti->mti_svname为名称的日志文件,并初始化llog_handle。 --record_marker(obd, llh, fsdb, CM_START, mti->mti_svname,\"add mdt\"):见下面 mgs_write_log_lov中的分析 --record_mount_opt(obd, llh, mti->mti_svname, fsdb->fsdb_mdtlov, 0):记录mount_opt到日志 --record_attach(obd, llh, mti->mti_svname, LUSTRE_MDS_NAME, mti->mti_uuid):见下面 mgs_write_log_lov中的分析 --record_setup(obd, llh, mti->mti_svname, mti->mti_uuid /* Ignored. Compatible with future. */, \"0\" /* MDT Index, default to zero. */, mti->mti_svname, 0 /* options */):类似于record_lov_setup --record_marker(obd, llh, fsdb, CM_END, mti->mti_svname, \"add mdt\"); --record_end_log(obd, &llh):见下面 mgs_write_log_lov中的分析 --name_create(&cliname, mti->mti_fsname, \"-client\"):cliname结果将是hust-client if (first_log) {//(注释:Append the mdt info to the client log) /* Start client log */ rc = mgs_write_log_lov(obd, fsdb, mti, cliname, fsdb->fsdb_clilov);:类比前面一个mgs_write_log_lov,这里传递的是第四五个参数分别为cliname和fsdb->fsdb_clilov,分别为hust-client和 hust-clilov。因此操作的日志文件为hust-client } -- name_create(&nodeuuid, libcfs_nid2str(mti->mti_nids[0]),/*\"_UUID\"*/\"\"); name_create(&mdcname, mti->mti_svname, \"-mdc\"); name_create(&mdcuuid, mdcname, \"_UUID\"); --record_start_log(obd, &llh, cliname):后面使用的llh都是这里返回的,而这里的cliname则是hust-client,其实是一个日志文件名。后面的日志记录都是在该文件中记录,此次之后在hust-client文件中记录的都是关于mdc的日志记录。 --rc = record_marker(obd, llh, fsdb, CM_END, mti->mti_svname, \"add mdc\"); --rc = record_end_log(obd, &llh); Mgs_write_log_lov(struct obd_device *obd, struct fs_db *fsdb, struct mgs_target_info *mti,char *logname, char *lovname) --这里参数中的logname对应于mti->mti_svname,lovname对应于fsdb->fsdb_mdtlov, 实际数据应该是hust-MDT0000和hust-mdtlov --OBD_ALLOC(lovdesc, sizeof(*lovdesc)):分配lov_desc结构 --初始化lovdesc --对于下面的系列操作在很多地方都会见到,在后面统一分析。 --record_start_log(obd, &llh, logname) --record_marker(obd, llh, fsdb, CM_START, lovname, \"lov setup\"):构造lustre_cfg,并传 递lustre_cfg::lcfg_command = LCFG_START,最后调用record_lcfg,根据lustre_cfg生成 一个日志记录(记录类型为OBD_CFG_REC),并将该记录写入到日志中。 --record_attach(obd, llh, lovname, \"lov\uuid):调用record_base,传递LCFG_ATTACH 命令,在record_base中根据参数构建lustre_cfg结构并通过record_lcfg记录到日志中, 这个记录的类型也是OBD_CFG_REC,表示是config记录 --record_lov_setup(obd, llh, lovname, lovdesc):这里使用了前面初始化完成的lovdesc --record_marker(obd, llh, fsdb, CM_END, lovname, \"lov setup\"):和前面record_marker一 样,只不过这里构造的lustre_cfg::cfg_command为LCFG_END. --record_end_log(obd, &llh):这个和record_start_log对应 record_start_log(struct obd_device *obd,struct llog_handle **llh, char *name) --static struct obd_uuid cfg_uuid = { .uuid = \"config_uuid\" } --llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT) --llog_create(ctxt, llh, NULL, name):打开MOUNT_CONFIGS_DIR/name,返回llh --llog_init_handle(*llh, LLOG_F_IS_PLAIN, &cfg_uuid):初始化llh record_marker(struct obd_device *obd, struct llog_handle *llh, struct fs_db *fsdb, __u32 flags, char *tgtname, char *comment) --声明三个关于config的变量 struct cfg_marker marker; struct lustre_cfg_bufs bufs; struct lustre_cfg *lcfg; --根据传递的参数初始化marker --lustre_cfg_bufs_reset(&bufs, NULL):设置lustre_cfs_bufs::lcfg_buf[0]为NULL --lustre_cfg_bufs_set(&bufs, 1, &marker, sizeof(marker)):设置lustre_cfs_bufs::lcfg_buf[1] 为marker --lcfg = lustre_cfg_new(LCFG_MARKER, &bufs):由bufs创建lustre_cfg结构 -- record_lcfg(obd, llh, lcfg):config log recording functions --struct llog_rec_hdr rec:声明记录头 --buflen = lustre_cfg_len(lcfg->lcfg_bufcount,lcfg->lcfg_buflens):计算lustre_cfg --初始化记录头部: rec.lrh_len = llog_data_len(buflen); rec.lrh_type = OBD_CFG_REC; --llog_write_rec(llh, &rec, NULL, 0, (void *)lcfg, -1):写记录到日志中 --lop->lop_write_rec(handle, rec, logcookies, numcookies, buf, idx) --llog_lvfs_write_rec:该函数前面已经讲解 --lustre_cfg_free(lcfg):释放lcfg record_attach(struct obd_device *obd, struct llog_handle *llh, char *devname, char *type, char *uuid) --这里传递的devname是hust-mdtlov,type是lov,uuid则是hust-mdtlov_UUID --record_base(obd,llh,devname,0,LCFG_ATTACH,type,uuid,0,0) --声明变量: struct lustre_cfg_bufs bufs; struct lustre_cfg *lcfg; --lustre_cfg_bufs_reset(&bufs, cfgname) --如果相应参数指定了,则调用lustre_cfg_bufs_set_string(&bufs, n, sn):其中n是 bufs中的index,sn代表存放在bufs[index]中的内容; --lcfg = lustre_cfg_new(cmd, &bufs):根据bufs生成lcfg --record_lcfg(obd, llh, lcfg):该函数在record_marker中已经讲解,见上面 --lustre_cfg_free(lcfg) record_lov_setup(struct obd_device *obd, struct llog_handle *llh, char *devname, struct lov_desc *desc) --声明变量: struct lustre_cfg_bufs bufs; struct lustre_cfg *lcfg; --lustre_cfg_bufs_reset(&bufs, devname) --lustre_cfg_bufs_set(&bufs, 1, desc, sizeof(*desc)) --lcfg = lustre_cfg_new(LCFG_SETUP, &bufs) --record_lcfg(obd, llh, lcfg) --lustre_cfg_free(lcfg) 这里的逻辑很简单,就是根据参数生成lustre_cfg,并通过lustre_cfg生成日志记录,并记录到日志中,这里也是走的record_lcfg,所以日志记录类型也是OBD_CFG_REC。 record_end_log(struct obd_device *obd, struct llog_handle **llh) --llog_close(*llh); 截止这里我们都没有看到lov_setup的踪影,那到底是在哪里调用到lov_setup呢?下面分析: 再看看server_start_targets的调用: Server_start_targets --CDEBUG(D_MOUNT, \"starting target %s\\n\:这一句打印信 息是starting target hust-MDTffff,也就是说lsi->lsi_ldd->ldd_svname为hust-MDTffff,但 是后面会改变(经mgs处理后返回),特别指出,下面会有对比! --如果target是ost或者mdt,而相应的oss或者mds没有启动,则调用lustre_start_simple --server_register_target(sb):在mgs上注册target,经过前面的分析过程我们知道对于 mdt,server_register_target会调用obd_set_info_async,并传递key为 KEY_REGISTER_TARGET,这样mgs收到该请求后就调用mgs_handle_target_reg, mgs_handel_target_reg--->mgs_write_log_target--->mgs_write_log_mdt/mgs_write_log_ost ---->写相应的日志记录到日志中,这个过程前面讲解过。 --server_register_mount(lsi->lsi_ldd->ldd_svname, sb, mnt):添加mount信息到全局的 server_mount_info_list中 --根据target相应的llog启动target,代码如下: memset(&cfg, 0, sizeof(cfg)); rc = lustre_process_log(sb, lsi->lsi_ldd->ldd_svname, &cfg):这里的 lsi->lsi_ldd->ldd_svname为hust-MD0000(这里要解释一下,为什么在 server_start_targets的第一条打印语句中,lsi->lsi_ldd->ldd_svname为 hust-MDTffff,这里怎么变成hust-MDT0000呢?原因是这样的,lustre系统最 开始都是分配给mdt的ldd_svname为hust-MDTffff,但是最后经过 server_register_target--->obd_set_info_async过程后,mgs会分配一个新的index 给mdt,并从mgs_target_info::mti_stripe_index中返回新的id,并在 mgs_target_info::mti_svname中返回新的svname,这就是我们前面看到的 hust-MDT0000,其index就是0000,如果再有新的mdt注册会分配0001等, 然后在从obd_set_info_async返回后,在server_register_target中的if (mti->mti_flags & LDD_F_REWRITE_LDD) 条件语句中调用 strncpy(ldd->ldd_svname, mti->mti_svname,sizeof(ldd->ldd_svname)) 将新 的svname拷贝到ldd->ldd_svname中,并调用ldd_write(&mgc->obd_lvfs_ctxt, ldd) 将其持久化)。下面我们关注server_start_targets--->lustre_process_log逻 辑。 server_start_targets(struct super_block *sb, struct vfsmount *mnt) -- 省略部分逻辑 -- lustre_process_log(sb, lsi->lsi_ldd->ldd_svname, &cfg):这里的lsi->lsi_ldd->ldd_svname 将是hust-MDT0000,下面专注lustre_process_log的逻辑。 lustre_process_log(struct super_block *sb, char *logname, struct config_llog_instance *cfg) --变量声明 struct lustre_cfg *lcfg; struct lustre_cfg_bufs bufs; struct lustre_sb_info *lsi = s2lsi(sb); struct obd_device *mgc = lsi->lsi_mgc; --lustre_cfg_bufs_reset(&bufs, mgc->obd_name):这里的mgc->obd_name是 MGC192.168.2.172@o2ib??? --lustre_cfg_bufs_set_string(&bufs, 1, logname):如果我们跟踪的是关于mdt的逻辑,这 里logname将是hust-MDT0000,前面在mgs_write_log_mdt中写过该日志文件。 --lustre_cfg_bufs_set(&bufs, 2, cfg, sizeof(*cfg)):这里是cfg是config_llog_instance结构 --lustre_cfg_bufs_set(&bufs, 3, &sb, sizeof(sb)) --lcfg = lustre_cfg_new(LCFG_LOG_START, &bufs) --obd_process_config(mgc, sizeof(*lcfg), lcfg) --mgc_process_config(struct obd_device *obd, obd_count len, void *buf):此时关于 lustre_cfg的命令是LCFG_LOG_START,处理如下: --变量声明和初始化,这里初始化都是从参数中获取相应变量 struct config_llog_data *cld; struct config_llog_instance *cfg; struct super_block *sb; char *logname = lustre_cfg_string(lcfg, 1); cfg = (struct config_llog_instance *)lustre_cfg_buf(lcfg, 2); sb = *(struct super_block **)lustre_cfg_buf(lcfg, 3); --debug信息显示:parse_log hust-MDT0000 from 0 --config_log_add(logname, cfg, sb) --根据参数logname,cfg,sb初始化config_llog_data *cld; --将cld连接到全局的config_llog_list中: list_add(&cld->cld_list_chain, &config_llog_list) --这个config_log_add的作用是什么呢??? --cld = config_log_find(logname, cfg):在config_llog_list中查找 --mgc_process_log(obd, cld) --该函数的注释耐人寻味:Get a config log from the MGS and process it. This func is called for both clients and servers,我理解的是无论是client 还 是server的config log都记录在mgs上,要从mgs处先获取config log 才能处理之??? --lsi = s2lsi(cld->cld_cfg.cfg_sb) --ctxt = llog_get_context(mgc, LLOG_CONFIG_REPL_CTXT) --mgc_enqueue(mgc->u.cli.cl_mgc_mgsexp, NULL, LDLM_PLAIN, NULL, LCK_CR, &flags, NULL, NULL, NULL, cld, 0, NULL, &lockh): get the config lock on the log --lctxt = llog_get_context(mgc, LLOG_CONFIG_ORIG_CTXT):这里要注意 的是在mgc_llog_init中我们调用llog_setup分别指定了 LLOG_CONFIG_REPL_CTXT和LLOG_CONFIG_ORIG_CTXT,但是按 我们想象中mgs端应该是LLOG_CONFIG_ORIG_CTXT,mgc端应该是 LLOG_CONFIG_REPL_CTXT啊,这里是因为我们是想将mgs端的 LLOG_CONFIG_ORIG_CTXT的日志拷贝的mgc的本地形成本地的 LLOG_CONFIG_ORIG_CTXT,这也是mgc_process_log的后面代码中体 现的。 --if(....) { mgc_copy_llog(mgc, ctxt, lctxt, cld->cld_logname) llog_ctxt_put(ctxt); ctxt = lctxt; } :代码中的注释为 “Copy the setup log locally if we can”。也就是如果可能 的话拷贝日志到本地,这里我们就是在lctxt代表local context,但是在 debug信息中没有关于mgc_copy_llog的调用,所以暂时忽略这个逻辑。 --class_config_parse_llog(ctxt, cld->cld_logname, &cld->cld_cfg) --这里我们忽略上面一段代码中的mgc_copy_llog逻辑,所以这里的 ctxt 就是ctxt = llog_get_context(mgc, LLOG_CONFIG_REPL_CTXT) 处返回的ctxt。这里的cld->cld_logname为hust-MDT0000 --debug信息:looking up llog hust-MDT0000 --llog_create(ctxt, &llh, NULL, name):打开日志文件hust-MDT0000 --llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL) --初始化llog_process_cat_data结构变量cd: cd.lpcd_first_idx = cfg->cfg_last_idx cd.lpcd_last_idx = 0 --llog_process(llh, class_config_llog_handler, cfg, &cd):关于 class_config_parse_llog--->llog_process这一逻辑下面单独讲解。 --更新cfg->cfg_last_idx = cd.lpcd_last_idx --llog_close(llh) --mgc_cancel(mgc->u.cli.cl_mgc_mgsexp, NULL, LCK_CR, &lockh):mgc释放锁,以便mgs回收之 --config_log_put(cld) --lustre_cfg_free(lcfg) class_config_parse_llog(struct llog_ctxt *ctxt, char *name,struct config_llog_instance *cfg) --struct llog_process_cat_data cd = {0, 0} --llog_create(ctxt, &llh, NULL, name) --如果我们跟踪mgc_process_log--->class_config_parse_llog逻辑,且不考虑 mgc_process_log--->mgc_copy_log的情况下,这里的ctxt对应为mgc的 LLOG_CONFIG_REPL_CTXT,其相应的操作函数为llog_client_ops。所以这里的 llog_create对应的是llog_client_create,代码如下: -- struct llogd_body req_body; struct llogd_body *body; struct llog_handle *handle; struct ptlrpc_request *req = NULL; __u32 size[3] = { sizeof(struct ptlrpc_body), sizeof(req_body) }; char *bufs[3] = { NULL, (char*)&req_body }; int bufcount = 2; --handle = llog_alloc_handle() -- req_body.lgd_logid = *logid:当logid不为空时才赋值 req_body.lgd_ctxt_idx = ctxt->loc_idx - 1:由replicator context获取original context -- if (name) { size[bufcount] = strlen(name) + 1; bufs[bufcount] = name:这里的name对应于日志文件名 bufcount++; } --ptlrpc_prep_req(imp,LUSTRE_LOG_VERSION, LLOG_ORIGIN_HANDLE_CREATE, bufcount, size, bufs):准备rpc请求 -- ptlrpc_queue_wait(req):发送请求,当收到reply时返回 --body = lustre_swab_repbuf(req, REPLY_REC_OFF, sizeof(*body), lustre_swab_llogd_body):根据reply获取body -- handle->lgh_id = body->lgd_logid:这里的logid是从reply中获得的 handle->lgh_ctxt = ctxt:这里的context还是原来的context -- handle会从参数中返回给调用上层 --llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL):初始化llog_handle -- cd.lpcd_first_idx = cfg->cfg_last_idx; cd.lpcd_last_idx = 0 --llog_process(llh, class_config_llog_handler, cfg, &cd) --根据传递的参数生成llog_process_info结构,并调用llog_process_thread处理之, 关于llog_process的处理分析见下面。 --cfg->cfg_last_idx = cd.lpcd_last_idx:更新cfg->cfg_last_idx --llog_close(llh) 上面class_config_parse_llog--->llog_create--->llog_client_create--->ptlrpc_prep_req逻辑中传递的是LLOG_ORIGIN_HANDLE_CREATE命令,到达mgs端处理函数为mgs_handle--->llog_origin_handle_create. llog_origin_handle_create(struct ptlrpc_request *req) --struct llogd_bodybody = lustre_swab_reqbuf(req, REQ_REC_OFF, sizeof(*body), lustre_swab_llogd_body) --struct llog_logid logid = &body->lgd_logid --name = lustre_msg_string(req->rq_reqmsg, REQ_REC_OFF + 1, 0):获取log文件名 --ctxt = llog_get_context(obd, body->lgd_ctxt_idx):注意这里的body->lgd_ctxt_idx在是从 class_config_parse_llog处理后的(由replica context--->original context转换) --llog_create(ctxt, &loghandle, logid, name):这里对应的是mgs的 LLOG_CONFIG_ORIG_CTXT,响应才日志操作函数集合为llog_lvfs_ops,所以这里的 llog_create对应的是llog_lvfs_create,代码如下: -- --lustre_pack_reply(req, 2, size, NULL):生成reply,注意这里并没有返回,返回则是在 mgs_handle的最后调用target_send_reply返回的。 -- body = lustre_msg_buf(req->rq_repmsg, REPLY_REC_OFF, sizeof(*body)) body->lgd_logid = loghandle->lgh_id --llog_close(loghandle) 当关于mgc端llog_create逻辑从mgs端返回的时候,我们又要分析mgc端mgc_process_log--->class_config_parse_llog--->llog_create后面的逻辑,于是就到了mgc_process_log--->class_config_parse_llog--->llog_init_handle,我们在class_config_parse_llog中分析(见上面)。 mgc_process_log--->class_config_parse_llog--->llog_process--->llog_process_thread llog_process_thread(void *arg) --根据参数初始化 struct llog_process_info *lpi = (struct llog_process_info *)arg; struct llog_handle *loghandle = lpi->lpi_loghandle; struct llog_log_hdr *llh = loghandle->lgh_hdr; struct llog_process_cat_data *cd = lpi->lpi_catdata; char *buf; 主要是对于给定的llog_handle中的所有日志记录调用lpi->lpi_cb进行处理。 --llog_next_block(loghandle, &saved_index, index, &cur_offset, buf, LLOG_CHUNK_SIZE):获取下一个block --循环对buf中的日志记录进行处理 for (rec = (struct llog_rec_hdr *)buf; (char *)rec < buf + LLOG_CHUNK_SIZE; rec = (struct llog_rec_hdr *)((char *)rec + rec->lrh_len)){ loghandle->lgh_cur_idx = rec->lrh_index; loghandle->lgh_cur_offset = (char *)rec - (char *)buf + last_offset; if (ext2_test_bit(index, llh->llh_bitmap)) { rc = lpi->lpi_cb(loghandle, rec,lpi->lpi_cbdata);// last_called_index = index; } ++index; if (index > last_index) } 由前面的调用路径: mgc_process_config--->mgc_process_log--->class_config_parse_llog---> llog_process(llh, class_config_llog_handler, cfg, &cd)我们知道在llog_process_thread中处理函数lpi->lpi_cb(loghandle, rec,lpi->lpi_cbdata)就是class_config_llog_handler,该函数处理的对象是日志(日志文件则是hust-MDT0000)中的一个个的记录,传递的参数将是llog_rec_hdr(这个记录头唯一标识一个记录)下面分析下该函数: class_config_llog_handler(struct llog_handle * handle, struct llog_rec_hdr *rec, void *data) --注意这里虽然有一个switch(rec->lrh_type),但是rec->lrh_type就只有OBD_CFG_REC 一种。 -- struct config_llog_instance *clli = data; int cfg_len = rec->lrh_len; char *cfg_buf = (char*) (rec + 1); --struct lustre_cfg *lcfg= (struct lustre_cfg *)cfg_buf --if (lcfg->lcfg_command == LCFG_MARKER) { struct cfg_marker *marker = lustre_cfg_buf(lcfg, 1) ....暂不关心 } --lustre_cfg_bufs_init(&bufs, lcfg):由lcfg得到bufs --lcfg_new = lustre_cfg_new(lcfg->lcfg_command, &bufs):由bufs和lcfg->lcfg_command 得到lcfg_new --class_process_config(lcfg_new):处理该lcfg_new --lustre_cfg_free(lcfg_new) --说明:对于这一层逻辑,我没有看到实质内容,在我们的实现中我们直接用 class_process_config即可,下面分析class_process_config: class_process_config(struct lustre_cfg *lcfg) --switch(lcfg->lcfg_command),我们这里关注的是LCFG_ATTACH,LCFG_SETUP 相应的处理函数为class_attach和class_setup class_attach(struct lustre_cfg *lcfg) --从lcfg中解析参数 --obd = class_newdev(typename, name):创建一个新设备 --obd的必要初始化 --如果在obd对应的obd_ops中定义了attach操作,则执行之: if (OBP(obd, attach)) {// rc = OBP(obd,attach)(obd, sizeof *lcfg, lcfg); } -- obd->obd_attached = 1:标志设备已经attach过了 class_setup(struct obd_device *obd, struct lustre_cfg *lcfg) -- obd->obd_uuid_hash = lustre_hash_init(\"UUID_HASH\ HASH_UUID_CUR_BITS, HASH_UUID_MAX_BITS, &uuid_hash_ops, 0); --exp = class_new_export(obd, &obd->obd_uuid) --obd_setup(obd, sizeof(*lcfg), lcfg):调用obd对应的obd_ops中的obd_setup --obd->obd_set_up = 1 在日志文件hust-MDT0000中记录了关于lov和mds的日志记录和,所以在上面的日志处理过程中分别会对对lov和mds进行attach和setup,但是lov和mds都没有attach操作,所以就直接执行的class_attach,而lov和mds对应的setup则分别是lov_setup和mds_setup。 至此我们理清了lov_setup和mds_setup的所有逻辑。。。。。。 (3)经(2)中分析,可知在(2)中对lov进行了setup,lov的lov_desc就是在lov_setup中建立的,下面我们分析lov_setup的实现: lov_setup(struct obd_device *obd, obd_count len, void *buf) -- struct lustre_cfg *lcfg = buf; struct lov_desc *desc; struct lov_obd *lov = &obd->u.lov; --desc = (struct lov_desc *)lustre_cfg_buf(lcfg, 1):获取lov_desc,这些lov_desc信息都是 在mgs_write_log_mdt--->mgs_write_log_lov中初始化并且记录到日志中的。 --初始化lov->lov_pools_hash_body:lustre_hash_init(......); --CFS_INIT_LIST_HEAD(&lov->lov_pool_list) --lov_ost_pool_init(&lov->lov_packed, 0) 这里我们看到lov_tgt_desc并没有在这里建立,这个应该是在lov_add_target中建立的。 下面我们就看lov_add_target是如何被调用到的。 在server_fill_super--->server_start_targets--->server_register_target会调用obd_set_info_async 调用形式为:obd_set_info_async(mgc->u.cli.cl_mgc_mgsexp, sizeof(KEY_REGISTER_TARGET), KEY_REGISTER_TARGET,sizeof(*mti), mti, NULL); 这里实际调用的是mgc_set_info_async,同时传递的key是KEY_REGISTER_TARGET。 在mgc_set_info_async中,当key为KEY_REGISTER_TARGET时,会调用mgc_target_register具体调用过程如下: Server_fill_super --server_start_targets --server_register_target --server_sb2mti(sb, mti): 根据sb获取mti(属于mgs_target_info结构) --obd_set_info_async(mgc->u.cli.cl_mgc_mgsexp,sizeof(KEY_REGISTER_TAR GET), KEY_REGISTER_TARGET,sizeof(*mti), mti, NULL); --mgc_set_info_async --mgc_target_register:当传递key是KEY_REGISTER_TARGET调用, 该函数发送target register信息给mgs --ptlrpc_prep_req(class_exp2cliimp(exp),LUSTRE_MGS_VERSIO N,MGS_TARGET_REG, 2, size, NULL); 准备rpc请求,请求的 opcode为MGS_TARGET_REG --ptlrpc_queue_wait(req) :发送请求 请求到底mgs端则在mgs_handle中当收到MGS_TARGET_REG命令时,会执行 mgs_handle_target_reg(struct ptlrpc_request *req);这个调用关系如下: mgs_handle(struct ptlrpc_request *req) --mgs_handle_target_reg(struct ptlrpc_request *req) --mgs_write_log_target(struct obd_device *obd,struct mgs_target_info *mti) --mgs_set_index(struct obd_device *obd, struct mgs_target_info *mti) --mgs_find_or_make_fsdb(obd, mti->mti_fsname, &fsdb) --mgs_write_log_mdt(struct obd_device *obd, struct fs_db *fsdb, struct mgs_target_info *mti)或者mgs_write_log_ost(struct obd_device *obd, struct fs_db *fsdb,struct mgs_target_info *mti) --mgs_write_log_params(obd, fsdb, mti) 下面分析一下mgs_write_log_ost(mgs_write_log_mdt前面已分析): mgs_write_log_ost(struct obd_device *obd, struct fs_db *fsdb,struct mgs_target_info *mti) --record_start_log(obd, &llh, mti->mti_svname) --record_marker(obd, llh, fsdb, CM_START, mti->mti_svname,\"add ost\") --record_attach(obd, llh, mti->mti_svname, \"obdfilter\"/*LUSTRE_OST_NAME*/, mti->mti_uuid) --record_setup(obd, llh, mti->mti_svname, \"dev\"/*ignored*/, \"type\"/*ignored*/, failout ? \"n\" : \"f\ --record_marker(obd, llh, fsdb, CM_END, mti->mti_svname, \"add ost\") --record_end_log(obd, &llh) --name_create(&logname, mti->mti_fsname, \"-MDT0000\"); --mgs_write_log_osc(obd, fsdb, mti, logname, fsdb->fsdb_mdtlov,flags); --name_create(&logname, mti->mti_fsname, \"-client\"); --mgs_write_log_osc(obd, fsdb, mti, logname, fsdb->fsdb_clilov,flags); 关于mount on client和mount on server有如下图表,摘自https://docs.google.com/viewer?a=v&q=cache:dB9L8htgS1AJ:wiki.lustre.org/images/1/11/LustreInternals_SampleLustreImplementation.pdf+lustre_start_mgc&hl=zh-CN&pid=bl&srcid=ADGEESjHpbAFnulTc3Lx3BLANBlB6ROOk2-zBFHdkKDV8P2BGpXzmDzVzExJQLkU2hX1z1Wvw3aPH8DUgD-rFid1HIIIIKGmHDZ-kzIiu_J71UaLsAKbqb9LD4NNzGvsuMS0YQJeq8FV&sig=AHIEtbRQHt89XHrdyduWh595dDN2ZLadTA Mount on clients • ll_fill_super calls into lustre_process_log > Set up buffers to hold struct lustre_cfg > Then call obd_process_log – Enqueue the configuration lock – Copy log to a local file on a server, unless we are the MGS – Call class_config_parse_llog – Wrapper for llog_process with iterator callback class_config_llog_handler – This calls a critical function: class_process_config • class_process_config performs > OBD device creation, attach, setup, adding connections • Unwind the stack, and end up in > client_common_fill_super Client common fill super • obd_connect to the lov and all the osc’s then ost’s • obd_connect to the mdc • mdc_get_status – fetch root fid • mdc_getattr – get root inode attributes • Instantiate the root inode and the root directory • You have a client file system! 明天继续分析上面的llog_ctxt相关,以及llog_test相关。 llog_test的启动 关于lustre_process_log--->obd_process_config --->***_process_config: 疑问: 1.找到llog_test_setup是哪个函数调用的? 2.找到LLOG_TEST_REPL_CTXT在哪用到? 3.找到transaction 在lustre中是否存在(除了server端和底层文件系统交互处用到的transaction之外),难道是obd_trans_info么?如果是obd_trans_info,那又是何时start何时commit呢? 因篇幅问题不能全部显示,请点此查看更多更全内容