cephfs kernel client写的过程

kernel 中ceph的客户端的源码在fs/ceph 中,这里我们以ceph的写操作为例。
从fs/ceph/file.c 中的ceph_file_fops 中可以知道写函数是ceph_write_iter
const struct file_operations ceph_file_fops = {
	.open = ceph_open,
	.release = ceph_release,
	.llseek = ceph_llseek,
	.read_iter = ceph_read_iter,
	.write_iter = ceph_write_iter,
	}

static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
	if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 ||
	    (iocb->ki_flags & IOCB_DIRECT) || (fi->flags & CEPH_F_SYNC) ||
	    (ci->i_ceph_flags & CEPH_I_ERROR_WRITE)) {
		struct ceph_snap_context *snapc;
		struct iov_iter data;
		inode_unlock(inode);


		#从这里可以知道client的写可以分为direct io和 bufffer io两种方式
		/* we might need to revert back to that point */
		data = *from;
		if (iocb->ki_flags & IOCB_DIRECT)
			written = ceph_direct_read_write(iocb, &data, snapc,
							 &prealloc_cf);
		else
			written = ceph_sync_write(iocb, &data, pos, snapc);
		if (written > 0)
			iov_iter_advance(from, written);
		ceph_put_snap_context(snapc);
	}
}
这里以direct io写为例
可以看到写的过程中主要分为三个request ,分别是ceph_osdc_new_request->ceph_osdc_start_request->ceph_osdc_wait_request
static ssize_t
ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
		       struct ceph_snap_context *snapc,
		       struct ceph_cap_flush **pcf)
{
	
	while (iov_iter_count(iter) > 0) {
		u64 size = dio_get_pagev_size(iter);
		size_t start = 0;
		ssize_t len;

		vino = ceph_vino(inode);
		#new request的主要作用是新建一个req,兵使用形参赋初值后,再将指针赋值给req
		req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
					    vino, pos, &size, 0,
					    1,
					    write ? CEPH_OSD_OP_WRITE :
						    CEPH_OSD_OP_READ,
					    flags, snapc,
					    ci->i_truncate_seq,
					    ci->i_truncate_size,
					    false);
		#start request的主要主要是调用submiet_quest来提交这个块设备
		ret = ceph_osdc_start_request(req->r_osdc, req, false);
		if (!ret)
		#这里会等待这个req被写入到磁盘中
			ret = ceph_osdc_wait_request(&fsc->client->osdc, req);

		
}
具体等待的函数如下:
int ceph_osdc_wait_request(struct ceph_osd_client *osdc,
			   struct ceph_osd_request *req)
{
	return wait_request_timeout(req, 0);
}
可见最终调用wait_for_completion_killable_timeout 来等待操作完成,从之前的分析指导wait_for_completion_killable_timeout 这个函数
在等待的过程中会让出cpu。这样就无法并发进行
static int wait_request_timeout(struct ceph_osd_request *req,
				unsigned long timeout)
{
	long left;

	dout("%s req %p tid %llu\n", __func__, req, req->r_tid);
	left = wait_for_completion_killable_timeout(&req->r_completion,
						ceph_timeout_jiffies(timeout));
	if (left <= 0) {
		left = left ?: -ETIMEDOUT;
		ceph_osdc_cancel_request(req);
	} else {
		left = req->r_result; /* completed */
	}

	return left;
}
从client写的过程可以知道,direct io的写会等到写完成后才返回,这里写完成可以指写入到磁盘中或者写入到kernel cache中,反正就是要等待
写完成后,才能进行下一次写过程。所以当个client 无法提高并发度,只能通过增减client的方式来增加并发度

你可能感兴趣的:(Linux,源码分析,ceph)