mds, meta data server
mds client 在内核fs层面实现, 最终还是需要通过net与mdsc通信
fs层面接收mdsc发来的命令, 并在fs层面完成具体操作
osd, object storage daemon
osd client 在内核net层面实现
mon, monitor daemon
include/linux/ceph/ceph_frag.h
frag, 高8位 "bits" + 低24位 "value"
fs/ceph/
caps.c
ceph_check_caps(), 检查caps, 公共函数
dir.c
ceph_dir_fops
ceph_dir_iops
file.c, 访问具体文件
struct file_operations ceph_file_fops
ceph_sync_write(), 与osd通信, 写入
ceph_osdc_new_request()
ceph_osdc_start_request()
ceph_osdc_wait_request()
inode.c, 使用rbtree 维护inode对应的一个或多个mds
ceph_file_iops, file inode 入口
通过和mdsc进行通信, 获取attr, xattr设置
ceph_setxattr() =>
int dirty = __ceph_mark_dirty_caps() 检查dirty cap并标记
__mark_inode_dirty(inode, dirty) 标识inode需要回写到磁盘
frag相关函数, 使用md5来为inode进行索引, 红黑树查找
__ceph_do_pending_vmtruncate() ????
ioctl.h,
ioctl.c,
ceph_ioctl(), 主入口
get/set layout, file/inode 在当前/远端上的layout,
参考struct ceph_ioctl_layout
ceph_choose_frag()
=> 调用__ceph_find_frag(),
frag->split_by == 0, 即frag没有child, 返回当前frag,
frag->split_by > 0,
ceph_frag_make_child(), 搜索child,
ceph_frag_contains_value(), 只比较value部分, 返回匹配的child
__ceph_find_frag(), rbtree搜索frag
从ci->i_fragtree.rb_node
locks.c, 与POSIX兼容锁实现, 见flock(2)和fcntl(2)
(struct file_lock)->fl_flags & FL_POSIX
(struct file_lock)->fl_flags & FL_FLOCK
ceph_lock(), fcntl lock
ceph_flock(), flock
=> ceph_lock_message()
ceph_lock_message(), mdsc构造并发现req, 告知lock 变动
mds_client.c
ceph_mdsc_do_request(), 构造并命令net ceph发送mds相关req
在同目录下多个文件中使用,
CEPH_MDS_OP_***
__register_request(),
wait_for_completion_killable()
ceph_invalidate_dir_request()
__register_request(), =>
__insert_request() 将request按红黑树搜索, 插入mdsc->request_tree.rb_node
__do_request()
__choose_mds()
__ceph_lookup_mds_session()
complete_request()
__ceph_lookup_mds_session(mds_client, int mds),
用session保护连接的唯一性 ???
complete_request(mds_client, request)
执行回调和complete_all()
__choose_mds(),
根据inode获取mds, 否则返回随机mds
ceph_mdsmap_get_state(), state >= CEPH_MDS_STATE_ACTIVE, 得到的mds才有意义
register_session()
ceph_con_open(), net/ceph/messenger.c
mdsmap.c, 导入mds map
snap.c
什么是snap?
snap是如何实现的?
ceph的snap实现有什么问题?
内核中的snap纯粹实现split ?
snap基于inode,
每个snap属于一个realm, snap像目录结构一样, 包含某个目录下的子目录,
类似改名之类变动dir的操作, 会改变realm的parent指向,
导致一个realm snap包含其parent的snap,
struct ceph_snap_realm, fs/ceph/super.h
flush_snaps(),
对mdsc->snap_flush_list的所有成员, 调用
__ceph_flush_snaps(), caps.c,
将snap相关的cap和inode信息提交到mds
ceph_update_snap_trace(), 连接snap的历史操作, 提交到mds,
所有对于snap的操作都要记录
struct ceph_mds_reply_info_parsed.snapblob
ri 新参数导入的realm
realm, 与ri同inode, 系统现有的
if (le64_to_cpu(ri->seq) > realm->seq) {
seq: version ??? 后续操作 ???
即ri要合并到realm
build_snap_context()
合并realm->num_prior_parent_snaps + realm->num_snaps,
保存在realm->cached_context
参考file.c, ceph_sync_write(),
ceph_osdc_new_request(..., ci->i_snap_realm->cached_context, ...)
rebuild_snap_realms(), 对realm和realm->children, 执行build_snap_context()
ceph_queue_cap_snap(),
当snap建立后, 所有对目标inode的写入操作都会预先合并到snap,
capsnap->ci 指向(struct ceph_inode_info *ci)
如果建立snap时, inode正在写入, capsnap->writing = 1,
如果写入完成, 即建立cap_snap, __ceph_finish_cap_snap()
ceph_handle_snap(), 主入口, 在mds_client.c, dispatch()中调用
对CEPH_SNAP_OP_SPLIT 操作, 需要分割现有realm, 或新建,
参数 u64 split从输入参数中转换获取,
使用split_inos[] => vino => inode => ceph_inode,
丢弃oldrealm = ci->i_snap_realm,
直接使用新建/查找到的现有realm
super.h,
struct ceph_inode_frag,
int split_by; 什么意思 ???, 在fill_inode() 中写入
super.c,
mount() =>
ceph_mount() =>
create_fs_client(), ceph_mdsc_init(), ceph_real_mount() =>
open_root_dentry() =>
ceph_mdsc_create_request(), CEPH_MDS_OP_GETATTR
ceph_mdsc_do_request(), 构造mdsc, 获取远端mds client上保存的attr
即本地负责mount, 并在本地构造根目录"/", 但对应的具体信息由mds保存,
所以在构造根目录之前, 需要首先访问mds
create_fs_client(),
struct ceph_fs_client,
fsc->wb_wq, "ceph-writeback"
fsc->pg_inv_wq, "ceph-pg-invalid"
fsc->trunc_wq, "ceph-trunc"
ceph_mdsc_init(fsc)
mdsc->fsc = fsc;
fsc->mdsc = mdsc;
fsc与mdsc需要相互对应
net/ceph/ 网络接口, 有EXPORT_SYMBOL
messenger.c
queue_con() 主要队列入口, 调用系统work执行ceph_connection->work
net/ceph/crush, crush核心算法接口
mapper.c, uniform, list, 等bucket
不同算法下的不同实现
bucket_uniform_choose()
crush_bucket_choose() =>
bucket_XXX_choose(), 如 uniform, list, tree, straw
bucket_tree_choose(), 不是数组实现的二叉树
以cursh_bucket_tree.num_nodes作为root, 使用hash生成的随机树?
bucket_straw_choose() =>
纯粹的随机数 ???
straw, 稻草
crush_do_rule(), 计算rule与其他参数对应的map,
CRUSH_RULE_CHOOSE_INDEP:
调用crush_choose() => list/tree/straw/...
注意参数, o+osize, ugly code
crush_choose(), 搜索leaf, 核心搜索函数
osd_client.c
ceph_connection_operations osd_con_ops 入口, 输入参数 ceph_msg
ceph_osdc_handle_map(), 导入osd_map
handle_reply(), 回应
ceph_osdc_readpages(), 从page获取osd_client
ceph_osdc_new_request()
ceph_osdc_start_request()
struct ceph_connection_operations osd_con_ops 接口
引用计数和认证
osdmap.c
crush_decode(), 解析crush_map, 导入bucket, rules
osdmap_apply_incremental()
从memory data导入osdmap
ceph_calc_object_layout(),
__lookup_pg_pool(), 红黑树搜索 poolid,
ceph_object_layout, 计算出ol的成员pgid (pool group id)和stripe_unit并返回
ceph_calc_pg_primary()
=> calc_pg_raw()
calc_pg_raw(), 从osdmap导入pool group
osdmap->pg_pools, pool 红黑树root
crush_find_rule(), 定位rule
__lookup_pg_mapping(osdmap->pg_temp),
crush_do_rule()
messenger.c 内部通讯接口,
fs/ceph/mds_client.c, __do_request() =>
ceph_con_send() 发送req, 被mds/osd/mon共同调用的公共接口
con_work() 初始化时调用, 线程
=>
try_read() 接收req, 接收并直接解析TCP报文
try_write()
ceph_con_init(), 见
ceph_con_init(monc->client->msgr, monc->con), mon_client.c
ceph_con_init(osdc->client->msgr, monc->o_con), osd_client.c
=> con_work()
read_partial(), 从指定的connection上获取指定长度的data,
调用 ceph_tcp_recvmsg()
try_read(),
con->state 维护状态机, (只建立conn时用?)
CONNECTING,
process_banner(), 确认对端IP, port
process_connect(), 由con->in_reply.tag 作出回应
con->in_tag, message exchange protocol,
include/linux/ceph/msgr.h, CEPH_MSGR_TAG_* 宏
try_write(),
con->sock == NULL, 建立新连接
ceph_tcp_connect(), 在内核中维护tcp con, 很麻烦
write_partial_kvec(),
struct kvec, 维护用户态下内存
include/linux/ceph/messenger.h, struct ceph_connection->out_kvec[8],
/* sending header/footer data */
write_partial_msg_pages(),
con->out_msg, 作为payload传输
完成全部写操作, con->state设成WRITE_PENDING
prepare_write_connect(), 根据con->peer_name.type,
获得protocol: MON/OSD/MDS
banner, auth等等
mon_clinet.c, monitor
pagevec.c, page vector 页表数组
ceph_get_direct_page_vector(),
(struct page) * num + user_pages
调用get_user_pages()