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

探索Lustre文件系统文件创建链路之客户端

作者头像
用户4700054
发布2023-02-26 14:43:10
8000
发布2023-02-26 14:43:10
举报

vfs层文件创建链路

  • vfs层是在客户端执行创建创建,首先是经过内核的syscallopen调用,最后调用的是具体文件系统实现的dir->i_op->atomic_open函数,这个函数是具体文件系统定义的。如下是vfs层的简要函数的定制和执行路径。
代码语言:javascript
复制
// 定义了系统调用open
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
	return do_sys_open(AT_FDCWD, filename, flags, mode);
}

// open函数的具体执行syscall函数
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
	 do_sys_openat2(dfd, filename, &how);
}


static long do_sys_openat2(int dfd, const char __user *filename,
			   struct open_how *how)
{
	struct file *f = do_filp_open(dfd, tmp, &op);

}


// 返回内核返回的struct file,这个是每个进程的fd所指向的结构
struct file *do_filp_open(int dfd, struct filename *pathname,
		const struct open_flags *op)
{
	filp = path_openat(&nd, op, flags | LOOKUP_RCU);
}


// 文件查找
static struct file *path_openat(struct nameidata *nd,
			const struct open_flags *op, unsigned flags)
{
	const char *s = path_init(nd, flags);
	while (!(error = link_path_walk(s, nd)) &&
		       (s = open_last_lookups(nd, file, op)) != NULL)
			;
}


// 快速查找
static const char *open_last_lookups(struct nameidata *nd,
		   struct file *file, const struct open_flags *op)
{

	
	lookup_open(nd, file, op, got_write);
}

// dentry的快速打开
static struct dentry *lookup_open(struct nameidata *nd, struct file *file,
				  const struct open_flags *op,
				  bool got_write)
{
	dentry = atomic_open(nd, dentry, file, open_flag, mode);
}

// 在这里即使执行具体文件系统定义的atomic_open函数
static struct dentry *atomic_open(struct nameidata *nd, struct dentry *dentry,
				  struct file *file,
				  int open_flag, umode_t mode)
{
	//  ll_atomic_open
	error = dir->i_op->atomic_open(dir, dentry, file,
				       open_to_namei_flags(open_flag), mode);
}

lustre客户端

ll_atomic_open入口函数
  • 文件创建的过程的本质是在父目录的inode的数据块添加一个dentry.在lustre中文件创建首先执行的是atomic_open函数,lustre文件系统和内核的vfs衔接是通过inode_operations ll_dir_inode_operations结构,这个是元数据的操作的函数结构体表其定义如下
代码语言:javascript
复制
const struct inode_operations ll_dir_inode_operations = {
	.mknod		= ll_mknod,
	.atomic_open	= ll_atomic_open,
	.lookup		= ll_lookup_nd,
	.create		= ll_create_nd,
	/* We need all these non-raw things for NFSD, to not patch it. */
	.unlink		= ll_unlink,
	.mkdir		= ll_mkdir,
	.rmdir		= ll_rmdir,
	.symlink	= ll_symlink,
	.link		= ll_link,
	.rename		= ll_rename,
	.setattr	= ll_setattr,
	.getattr	= ll_getattr,
	.permission	= ll_inode_permission,
#ifdef HAVE_IOP_XATTR
	.setxattr	= ll_setxattr,
	.getxattr	= ll_getxattr,
	.removexattr	= ll_removexattr,
#endif
	.listxattr	= ll_listxattr,
	.get_acl	= ll_get_acl,
#ifdef HAVE_IOP_SET_ACL
	.set_acl	= ll_set_acl,
#endif
};
  • lustre创建文件首先执行的是ll_atomic_open,这个函数核心逻辑分为两部分的核心逻辑,一个是查找函数ll_lookup_it,另外一个是创建文件函数ll_create_it.ll_atomic_open将lookup/create/open操作在一个接口里完成主要用于性能优化,如下把最核心的函数列举出来。
代码语言:javascript
复制
static int ll_atomic_open(struct inode *dir, struct dentry *dentry,
			  struct file *file, unsigned open_flags,
			  umode_t mode ll_last_arg)
{
	struct lookup_intent *it;
	struct dentry *de;

	// 创建文件时候的查找过程,带着需要文件的父目录和文件名称,请求mds创建文件的元数据信息
	de = ll_lookup_it(dir, dentry, it, &secctx, &secctxlen, &pca, encrypt,&encctx, &encctxlen);

	// 客户端测文件的创建过程,需要设置client的obd层的初始化和设置
	rc=ll_create_it(dir, dentry, it, secctx, secctxlen,
					  encrypt, encctx, encctxlen,
					  open_flags);
}
  • lustre创建文件的时候仅仅是客户端的mdcmds进行交互,所以这里涉及的obd stack仅仅是mdc
ll_lookup_it函数
  • ll_lookup_it函数的核心逻辑负责去创建文件的父目录查找当前目标文件,其中顺着链路调用:ll_lookup_it->ll_prep_md_op_data->md_intent_lock->req_capsule_server_get->ll_lookup_it_finish。这个链路带着意向锁请求到MDS,MDS负责创建对应文件的元数据,通过网络在回给这个函数
代码语言:javascript
复制
static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
				   struct lookup_intent *it,
				   void **secctx, __u32 *secctxlen,
				   struct pcc_create_attach *pca,
				   bool encrypt,
				   void **encctx, __u32 *encctxlen)
{
	struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
	struct dentry *save = dentry, *retval;
	struct ptlrpc_request *req = NULL;
	struct md_op_data *op_data = NULL;
	struct lov_user_md *lum = NULL;
	__u32 opc;
	int rc;

	// 准备请求mgs的文件的父目录和文件名称
	op_data = ll_prep_md_op_data(NULL, parent, NULL, fname.disk_name.name,fname.disk_name.len, 0, opc, NULL);

	// 添加意向锁,同时设置lustre的锁的回调函数请求mds来为新文件创建元数据信息
	rc = md_intent_lock(ll_i2mdexp(parent), op_data, it, &req,
			    &ll_md_blocking_ast, 0)
	{
		// 在lmv层添加意向锁
		lmv_intent_lock() {
			// 带有意向锁的查找,需要检查是否有锁冲突或者失效
			lmv_intent_lookup() {
				// 通过mdc请求意向锁
				mdc_intent_lock() {
					//网络层的请求发送
				}
			}
		}
	}
	// 完成查找后的逻辑处理,到这里MDS端文件的元数据inode已经在mds端创建
	rc = ll_lookup_it_finish(req,....)
		{
			// 初始化inode的dentry
			ll_splice_alias(inode, *de)
		}
	return retval;
}
ll_create_it函数
  • ll_create_it函数是文件请求到MDS后返回结构,根据这些信息去初始化客户端的OBD DEVICE STACK.这个函数最核心的逻辑是ll_create_node,基本做了从mds获取meta,设置客户端的lov和lmv信息,同时设置文件在vfs层的操作函数表,最后把dentryinode进行关联起来
代码语言:javascript
复制
// name=demo1.txt, dir=[0x200000007:0x1:0x0](00000000c5a5737f), intent=open|creat
static int ll_create_it(struct inode *dir, struct dentry *dentry,
			struct lookup_intent *it,
			void *secctx, __u32 secctxlen, bool encrypt,
			void *encctx, __u32 encctxlen, unsigned int open_flags)
{
	struct inode *inode;
	__u64 bits = 0;
	int rc = 0;
	ENTRY;


	inode = ll_create_node(dir, it)
	{
		// inode准备工作
		ll_prep_inode(&inode, &request->rq_pill, dir->i_sb, it)
		{
			// 从服务端拿到meta信息
			md_get_lustre_md(){
				mdc_get_lustre_md() {
					// 从mds获取新文件的meta
					body=req_capsule_server_get(pill, &RMF_MDT_BODY);
					// 设置新文件的lmv信息
					lmv = req_capsule_server_sized_get(pill, &RMF_MDT_MD, lmv_size);
				}
			}
			// 
			*inode = ll_iget(sb, cl_fid_build_ino(fid1, api32), &md)
			{
		 		// 设置lustre文件的inode->i_op/inode->i_fop/inode->i_mapping 操作函数表
				rc = ll_read_inode2(inode, md)
				cl_object_find(...)
				{
					// 通过多层的调用进入如下两个函数
					top = lu_object_find(env, dev, f, conf)
					{
						// cache中有则返回,没有则创建
						lu_object_find_at(...)
						{
							lu_object_alloc(env, dev, f)
							{
								// 这里是客户端的操作stack,在外层代码中详细展示出来
								vvp_object_alloc()
								
							}
						}
					}
					// 把对象添加到客户端的stack操作列表
					obj = lu_object_locate(top->lo_header, dev->ld_type);
					
				}
			}
		}
	}

	// 新文件的dentry和新创建的inode进行关联
	d_instantiate(dentry, inode);
	RETURN(0);
}
  • lu_object_alloc开始就开始初始化文件对象的OBD DEVICE STACK.这里可以看到一个对象的函数操作stack会经历:vvp->lov->lovsub->osc层,这个是文件IO读写的必须经历的函数操作栈
代码语言:javascript
复制
// vvp层对象初始化
vvp_object_alloc(){
	// lov对象申请
	lov_object_alloc()
	// lov对象初始化
	lov_object_init()
	{
		// lov初始化布局
		lov_init_composite()
		{
			// raid0的布局初始化
			lov_init_raid0() 
			{
				// 
				lu_object_find_at() 
				{
					// lovsub对象初始化,这是涉及到多个OSC
					lovsub_object_alloc()
					lu_object_start()
					{
						lovsub_object_init()
						{
							// osc初始化
							osc_object_alloc()
						}
					}
				}
				// lov子对象初始化
				lov_init_sub()
			}
		}
	}												
}	
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-10-24,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • vfs层文件创建链路
  • lustre客户端
    • ll_atomic_open入口函数
      • ll_lookup_it函数
        • ll_create_it函数
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档