前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >探索Lustre文件系统文件创建实现上篇之服务端

探索Lustre文件系统文件创建实现上篇之服务端

作者头像
用户4700054
发布2023-02-26 14:44:13
7440
发布2023-02-26 14:44:13
举报

特殊的mdt0

  • mdt0是lustre元数据服务的注册开启的地方,注册处理客户端请求的各种handler.mdt初始化的通过mount时候读取CONFIGS/{fsname}-MDT0000文件数据进行mds obd初始化,mds初始化的读取bigfs-MDT0000-mdtlov、bigfs-MDT0000(mdt0)、bigfs-OST0001(osc1)、bigfs-OST0002(osc2),用llog_reader解析配置文件如下:
代码语言:javascript
复制
// 通过llog_reader读取mdt的配置文件
$ llog_reader  bigfs-MDT0000 
// 这是rec的记录的长度和偏移量
rec #1 type=10620000 len=224 offset 8192
rec #2 type=10620000 len=136 offset 8416
rec #3 type=10620000 len=176 offset 8552
rec #4 type=10620000 len=224 offset 8728
rec #5 type=10620000 len=224 offset 8952
rec #6 type=10620000 len=120 offset 9176
rec #7 type=10620000 len=112 offset 9296
rec #8 type=10620000 len=160 offset 9408
rec #9 type=10620000 len=224 offset 9568
rec #10 type=10620000 len=224 offset 9792
rec #11 type=10620000 len=80 offset 10016
rec #12 type=10620000 len=144 offset 10096
rec #13 type=10620000 len=144 offset 10240
rec #14 type=10620000 len=136 offset 10384
rec #15 type=10620000 len=224 offset 10520
rec #16 type=10620000 len=224 offset 10744
rec #17 type=10620000 len=80 offset 10968
rec #18 type=10620000 len=144 offset 11048
rec #19 type=10620000 len=144 offset 11192
rec #20 type=10620000 len=136 offset 11336
rec #21 type=10620000 len=224 offset 11472

// 这里是mds端初始化的需要的配置
Header size : 8192       llh_size : 80
Time : Wed Oct 19 03:08:38 2022
Number of records: 21   cat_idx: 0      last_idx: 21
Target uuid : config_uuid
-----------------------
#01 (224)marker   2 (flags=0x01, v2.15.0.0) bigfs-MDT0000-mdtlov 'lov setup' Wed Oct 19 03:08:38 2022-
#02 (136)attach    0:bigfs-MDT0000-mdtlov  1:lov  2:bigfs-MDT0000-mdtlov_UUID  
#03 (176)lov_setup 0:bigfs-MDT0000-mdtlov  1:(struct lov_desc)
                uuid=bigfs-MDT0000-mdtlov_UUID  stripe:cnt=1 size=1048576 offset=18446744073709551615 pattern=0x1
#04 (224)END   marker   2 (flags=0x02, v2.15.0.0) bigfs-MDT0000-mdtlov 'lov setup' Wed Oct 19 03:08:38 2022-
#05 (224)marker   3 (flags=0x01, v2.15.0.0) bigfs-MDT0000   'add mdt' Wed Oct 19 03:08:38 2022-
#06 (120)attach    0:bigfs-MDT0000  1:mdt  2:bigfs-MDT0000_UUID  
#07 (112)mount_option 0:  1:bigfs-MDT0000  2:bigfs-MDT0000-mdtlov  
#08 (160)setup     0:bigfs-MDT0000  1:bigfs-MDT0000_UUID  2:0  3:bigfs-MDT0000-mdtlov  4:f  
#09 (224)END   marker   3 (flags=0x02, v2.15.0.0) bigfs-MDT0000   'add mdt' Wed Oct 19 03:08:38 2022-
#10 (224)marker   9 (flags=0x01, v2.15.0.0) bigfs-OST0001   'add osc' Wed Oct 19 03:08:38 2022-
#11 (080)add_uuid  nid=10.211.55.5@tcp(0x200000ad33705)  0:  1:10.211.55.5@tcp  
#12 (144)attach    0:bigfs-OST0001-osc-MDT0000  1:osc  2:bigfs-MDT0000-mdtlov_UUID  
#13 (144)setup     0:bigfs-OST0001-osc-MDT0000  1:bigfs-OST0001_UUID  2:10.211.55.5@tcp  
#14 (136)lov_modify_tgts add 0:bigfs-MDT0000-mdtlov  1:bigfs-OST0001_UUID  2:1  3:1  
#15 (224)END   marker   9 (flags=0x02, v2.15.0.0) bigfs-OST0001   'add osc' Wed Oct 19 03:08:38 2022-
#16 (224)marker  12 (flags=0x01, v2.15.0.0) bigfs-OST0002   'add osc' Wed Oct 19 03:08:38 2022-
#17 (080)add_uuid  nid=10.211.55.5@tcp(0x200000ad33705)  0:  1:10.211.55.5@tcp  
#18 (144)attach    0:bigfs-OST0002-osc-MDT0000  1:osc  2:bigfs-MDT0000-mdtlov_UUID  
#19 (144)setup     0:bigfs-OST0002-osc-MDT0000  1:bigfs-OST0002_UUID  2:10.211.55.5@tcp  
#20 (136)lov_modify_tgts add 0:bigfs-MDT0000-mdtlov  1:bigfs-OST0002_UUID  2:2  3:1  
#21 (224)END   marker  12 (flags=0x02, v2.15.0.0) bigfs-OST0002   'add osc' Wed Oct 19 03:08:38 2022-
[root@CentOS-Lustre-Server /mnt/mgt_mdt/CONFIGS]$ 
  • mdt_init0的核心逻辑负责初始化mdtobd stack操作栈,如下是mdt0初始化的核心函数,这个做了mdt操作栈初始化->fld的初始化->seq初始化->注册intent回调函数->io表初始化->mds faiover的rpc设置->设置参数调整的函数表->quota初始化->分布式锁客户端初始化->lustre客户端驱逐服务等核心逻辑的初始化
代码语言:javascript
复制
static int mdt_init0(....)
{


	// 根据obd name查找挂在点,返回lustre_mount_info信息
	server_get_mount(dev);

	// 根据CONFIGS/{fsname}-MDT0000 初始化mdt的操作栈
	mdt_stack_init((struct lu_env *)env, m, cfg);

	// mdt fid存储数据库初始化
	mdt_fld_init(env, mdt_obd_name(m), m)
	{
		fld_server_init(...)
	}

	// mdt中seq_controller和seq_server的初始化
	mdt_seq_init(env, m)
	{
		// seq_controller服务初始化
		seq_server_init(LUSTRE_SEQ_CONTROLLER,...);
		// seq_server的初始化
		seq_server_init(LUSTRE_SEQ_SERVER,...);
		// seq_server通过seq_client来和seq_controller交互
		mdt_seq_init_cli(env, mdt);
	}
	// 设置intent锁的回调函数
	ldlm_register_intent(m->mdt_namespace, mdt_intent_policy);

	// mdt请求处理函数,各种请求处理handler的注册
	tgt_init(...);

	// mdt中事务的回调函数初始化
	mdt_fs_setup(env, m, obd, lsi);

	// 初始化mds端本地oi表
	local_oid_storage_init(env, m->mdt_bottom, &fid, &m->mdt_los);

	// mds中rpc failover的设置
	tgt_adapt_sptlrpc_conf(&m->mdt_lut);

	// mds端参数设置的初始化,设置参数设置的操作函数
	 mdt_tunables_init(m, dev);

	// mdt quota的初始化
	 mdt_quota_init(env, m, cfg);
	
	// mdt端分布式锁的客户端初始化
	ptlrpc_init_client(LDLM_CB_REQUEST_PORTAL, LDLM_CB_REPLY_PORTAL,
			   "mdt_ldlm_client", m->mdt_ldlm_client);

	// lustre客户端驱逐的服务初始化
	ping_evictor_start();


}
  • mds的整体OBD Stack如下:

MDS端文件创建链路实现

lookup过程
  • lookup过程做了几个事情,第一是查看root节点的信息;第二是父目录的meta信息;第三父目录加锁的过程;第四是在父目录中查找新文件的fid
代码语言:javascript
复制
int mdt_reint_open(struct mdt_thread_info *info, struct mdt_lock_handle *lhc)
{
	// 查找root节点信息,根据请求加锁
	result = mdt_lock_root_xattr(info, mdt)
	{
		md_root = mdt_object_find(...)
		{
			o = lu_object_find(...)
			{
				lu_object_find_at(...)
			}
		}
	}
	// 查找新文件的父目录meta信息,其定义结构为struct mdt_object
	parent = mdt_object_find(...)
	{
		o = lu_object_find(...)
		{
			lu_object_find_at(...)
		}
	}
	// 加锁:检查父目录下的文件是否存在,如果存在则在父目录存在添加LCK_PR锁;否则添加LCK_PW,新文件是第一创建,所以会在父目录加CK_PW锁
	lock_mode = mdt_open_lock_mode(...)
	{
		mdo_lookup(...)
		{
			mdd_lookup(...)
			{
				__mdd_lookup(...)
				{
					// dt_lookup 根据文件名称查找dentry从中获取到inode,如果inode存在从inode获取fid信息,从inode扩展属性中获取fid
					osd_index_ea_lookup(...)
					{
						osd_ea_lookup_rec(...)
					}
				}
			}
		}
	}

	// 这里查找新文件是否存在,这里有一个疑惑,父目录已经能判断出新文件是否存在,这里为何还要查找一次
	result = mdo_lookup(info->mti_env, mdt_object_child(parent),
				    &rr->rr_name, child_fid, &info->mti_spec)
	{
		// 查找新创建的目标文件,如果存在返回0,否则返回其他
		mdd_lookup(...)
			{
				__mdd_lookup(...)
				{
					// 注意新文件在父目录里压根不存在
					dt_lookup(...)
					{
						// 根据文件名称查找dentry从中获取到inode,如果inode存在从inode获取fid信息
						osd_index_ea_lookup(...)
						{
							osd_ea_lookup_rec(...)
						}
					}
				}
			}
		}
	}
	result = mdo_create(....);
	rc = mdt_finish_open(...);
	

}
create过程
  • create阶段是做了几个事情,第一是获取root节点的信息,第二是获取新文件的父目录meta,第三查看目标文件是否存在,第四是创建新文件的meta信息;第五是开启事务准备写入新文件meta信息,最后完成新文件创建成功后续操作。这个过程非常复杂,核心的设计理念可以理解为虚函数(函数指针)
代码语言:javascript
复制
int mdt_reint_open(struct mdt_thread_info *info, struct mdt_lock_handle *lhc)
{
    /***************这是lookup过程***************/
	// 查找root节点信息,根据请求加锁
	result = mdt_lock_root_xattr(info, mdt)
	// 查找新文件的父目录meta信息
	parent = mdt_object_find(...)
	// 加锁:检查父目录下的文件是否存在,如果存在则在父目录存在添加LCK_PR锁;否则添加LCK_PW,新文件是第一创建,所以会在父目录加CK_PW锁
	lock_mode = mdt_open_lock_mode(...)

	// 这里查找新文件是否存在
	result = mdo_lookup(info->mti_env, mdt_object_child(parent),
				    &rr->rr_name, child_fid, &info->mti_spec)



    /***************这是create过程***************/
	// 这里是创建新文件的meta
	child = mdt_object_new(info->mti_env, mdt, child_fid)
	{
		lu_object_find(...)
		{
			// 这里调用的是 lu_object_alloc 实际call的是mdt_object_alloc
			lu_object_find_at(...)
			{
				lu_object_alloc(...){
					mdt_object_alloc(...){
						// lu_object_init实际调用的是mdt_object_init
						mdt_object_init(...){
						// call ldo_object_alloc
							mdd_object_alloc(...)
						}
					}
				}
				lu_object_start(env, dev, o, conf)
				{
					
					loo_object_init(...)
					{
						// loo_object_init
						mdt_object_init(...)
						{
							//ldo_object_alloc
							lod_object_alloc(...)
							{
								lu_object_init(...)
							}
						}
						// loo_object_init
						lod_object_init(...)
						{
							lod_fld_lookup(...)
							{
								fld_server_lookup(....)
								{
								
									fld_local_lookup(...)
								}
							}
							// ldo_object_alloc
							osd_object_alloc(...)
							{
								dt_object_init(...)
							}
						}
						osd_object_init(...)
					}
				}
				loo_object_start(...)
				{
					mdd_object_start(....)
				}
				
			}
		}
	}
	result = mdo_create(info->mti_env, mdt_object_child(parent),
				    &rr->rr_name, mdt_object_child(child),
				    &info->mti_spec, &info->mti_attr);
	{
		// mdo_create实际调用mdd_create
		mdd_create(...)
		{
			// 执行事务
			handle = mdd_trans_create(env, mdd)
			{
				// dt_trans_create
				osd_trans_create(...)
			}
			// 准备文件的link属性,link属性包含了父目录的fid和自身文件名称
			// parent-fid=[0x200000007:0x1:0x0],filename=demo1.txt
			rc = mdd_linkea_prepare(...);
			rc = mdd_declare_create(...)
			{
				mdd_declare_create_object(...)
				{
					// 这个函数准备
					mdd_declare_create_object_internal(...)
					{
						mdo_declare_create_object(...)
						{
				// dt_declare_create call do_declare_create
							osd_declare_create(...)
				// 
							mdo_declare_xattr_set(...)
							{
								// 这个函数内调用dt_declare_attr_set函数指针
								lod_declare_attr_set(...)
								{
									// 获取每个ost的容量信息,通过lod_ost_alloc_rr函数决定数据应该写到哪个ost上
									lod_declare_striped_create(...)
								}
							}			
						}
					}
				}
			}
			// 开启事务准备写入
			rc = mdd_trans_start(env, mdd, handle)
			{
				// 执行dt_trans_start函数指针,写入mds端的数据时候的事务
				top_trans_start(...)
				{
					// 开启mds端osd的事务
					osd_trans_start(...)
				}
			}
			rc = mdd_create_object(...)
			{
				mdd_create_object_internal(...)
				{
					// mdo_create_object->dt_create
					lod_create(...)
					{
						lod_sub_create(...)
						{
							// dt_create
							osd_create(...)
							{
								fid_is_on_ost()
								osd_ea_fid_set()
								__osd_oi_insert()
								{
									osd_oi_insert()
								}
								osd_idc_find_and_init()
								
							}
							
						}
						lod_striped_create()
						{
							for (j = 0; j < lc_stripe_count; j++)
							{
								lod_sub_create()
								{
									// dt_create指向osp_create
									osp_create(...)
								}
							}
							lod_generate_and_set_lovea()
							{
								lod_generate_lovea(...)
								lod_sub_xattr_set(XATTR_NAME_LOV)
								{
									// dt_xattr_set函数指针,设置文件的trusted.lov
									osd_xattr_set(...)
								}
							}
						}
					}
				}
				mdd_object_initialize(...)
			}
			__mdd_index_insert(...)
			{
				__mdd_index_insert_only()
				{
					// dt_insert函数指针
					osd_index_ea_insert()
					
				}
			}
			mdd_links_add(...)
			{
				mdd_links_rename()
				{
					mdd_links_write(){
						// mdo_xattr_set 函数指针
						lod_xattr_set()
						{
							// lod_sub_xattr_set函数指针
							lod_xattr_set_internal()
							{
								lod_sub_xattr_set()
								{
									// dt_xattr_set
									// 设置文件的trusted.link
									osd_xattr_set()
								}
							}
						}
					}
				}
			}
			
		}
		mdd_changelog_ns_store(...)
		mdd_trans_stop(...)
		{
			top_trans_stop()
			{
				osd_trans_stop()
			}
		}
	}
	rc = mdt_finish_open(...)
	{
		mdt_mfd_open(...)
		{
			// mo_open
			mdd_open()
			mdt_mfd_new()
		}
	}
	
}

OSS端文件创建链路实现

  • ost端的核心逻辑是创建ost端的对应的文件分片对象,ost挂在启动后,所有的请求会在tgt_request_handle进行处理.MDS端把文件对应的元数据存储后,通过MDS的osp请求发送到ost端,ost处理对应的请求.
代码语言:javascript
复制
// 内核线程启动ptl_main函数接受来自rpc的请求,然后进行处理
static int ptlrpc_main(void *arg)
{
	while (!ptlrpc_thread_stopping(thread))) 
	{
		// 请求数据处理函数
		ptlrpc_server_handle_request(...)
		{
			// 函数指针 so_req_handler
			tgt_request_handle(...)
			{
				target_handle_connect(...)
				{
					// obd_connect函数指针
					ofd_obd_connect(...)
					{
						tgt_client_new(...)
						{
							// 写入新文件对应的对象分片
							tgt_client_data_update(...)
							{
								//dt_trans_create函数指针
								osd_trans_create(...)
								//dt_declare_record_write函数指针
								osd_declare_write(...)
								// dt_trans_start_local函数指针
								osd_trans_start(...)
								tgt_client_data_write(...)
								// dt_trans_stop函数指针
								osd_trans_stop(...)
								
								
							}
						}
					}
					 
				}
			}
		}
	}
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-11-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 存储内核技术交流 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 特殊的mdt0
  • MDS端文件创建链路实现
    • lookup过程
      • create过程
      • OSS端文件创建链路实现
      相关产品与服务
      数据保险箱
      数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档