Ceph版本:14.2.22
Server::handle_client_mkdir
文件路径:ceph/src/mds/Server.cc
当客户端发送创建目录文件请求到mds服务端时,mds会根据客户端请求类型,执行Server::handle_client_mkdir函数;该函数主要实现以下功能:
- 从mdr中解析出客户端请求;
- 从客户端请求中解析出将要创建的目录文件是否是隐藏文件,是则终止流程,否则继续流程;
- 根据将要创建的目录文件路径构造出该目录的CDentry;
- 为将要创建的目录文件构造新的CInode,并填充CInode信息;
void Server::handle_client_mkdir(MDRequestRef &mdr)
{
//获取客户端请求
const MClientRequest::const_ref &req = mdr->client_request;
//如果新建的目录是.或者..隐藏目录,直接返回
if (req->get_filepath().is_last_dot_or_dotdot())
{
respond_to_request(mdr, -EEXIST);
return;
}
MutationImpl::LockOpVec lov;
//根据目录路径解析出本级目录关联的CDentry,并对父目录和本级目录的相关联的结构加锁
CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, lov, false, false, false);
if (!dn)
return;
if (mdr->snapid != CEPH_NOSNAP)
{
respond_to_request(mdr, -EROFS);
return;
}
//获取父级目录CDir
CDir *dir = dn->get_dir();
//获取父级目录CInode
CInode *diri = dir->get_inode();
//对父级目录CInode的authlock锁加读操作锁
lov.add_rdlock(&diri->authlock);
//加锁是否成功?
if (!mds->locker->acquire_locks(mdr, lov))
return;
// mkdir check access
//检查客户端对父级目录是否有写权限
if (!check_access(mdr, diri, MAY_WRITE))
return;
//检查父级目录的分片大小是否足够
if (!check_fragment_space(mdr, dir))
return;
// new inode
unsigned mode = req->head.args.mkdir.mode;
mode &= ~S_IFMT;
mode |= S_IFDIR;
//创建本级目录CInode,inode号与req->head.ino绑定
CInode *newi = prepare_new_inode(mdr, dn->get_dir(), inodeno_t(req->head.ino), mode);
ceph_assert(newi);
// it's a directory.
//将本级目录关联的CDentry与本级目录CInode建立链接关系
dn->push_projected_linkage(newi);
//填充本级目录CInode内容
newi->inode.version = dn->pre_dirty();
newi->inode.rstat.rsubdirs = 1;
newi->inode.update_backtrace();
snapid_t follows = mdcache->get_global_snaprealm()->get_newest_seq();
SnapRealm *realm = dn->get_dir()->inode->find_snaprealm();
ceph_assert(follows >= realm->get_newest_seq());
dout(12) << " follows " << follows << dendl;
ceph_assert(dn->first == follows + 1);
newi->first = dn->first;
// ...and that new dir is empty.
//创建本级目录CDir
CDir *newdir = newi->get_or_open_dirfrag(mdcache, frag_t());
//填充本级目录CDir内容
newdir->state_set(CDir::STATE_CREATING);
newdir->mark_complete();
newdir->fnode.version = newdir->pre_dirty();
// prepare finisher
//获取log分片
mdr->ls = mdlog->get_current_segment();
//创建一个新的log事件
EUpdate *le = new EUpdate(mdlog, "mkdir");
//启动log事件
mdlog->start_entry(le);
//将客户端ID添加到log事件中
le->metablob.add_client_req(req->get_reqid(), req->get_oldest_client_tid());
journal_allocated_inos(mdr, &le->metablob);
mdcache->predirty_journal_parents(mdr, &le->metablob, newi, dn->get_dir(), PREDIRTY_PRIMARY | PREDIRTY_DIR, 1);
//将本级目录关联的Dentry添加到log事件中
le->metablob.add_primary_dentry(dn, newi, true, true);
//将本级目录CDir添加到log事件中
le->metablob.add_new_dir(newdir); // dirty AND complete AND new
// issue a cap on the directory
int cmode = CEPH_FILE_MODE_RDWR;
//获取新的Capability
Capability *cap = mds->locker->issue_new_caps(newi, cmode, mdr->session, realm, req->is_replay());
if (cap)
{
cap->set_wanted(0);
// put locks in excl mode
newi->filelock.set_state(LOCK_EXCL);
newi->authlock.set_state(LOCK_EXCL);
newi->xattrlock.set_state(LOCK_EXCL);
}
// make sure this inode gets into the journal
//将当前目录CInode的序号添加到log事件中
le->metablob.add_opened_ino(newi->ino());
//处理日志
journal_and_reply(mdr, newi, dn, le, new C_MDS_mknod_finish(this, mdr, dn, newi));
// We hit_dir (via hit_inode) in our finish callback, but by then we might
// have overshot the split size (multiple mkdir in flight), so here is
// an early chance to split the dir if this mkdir makes it oversized.
//判断父级目录CDir是否需要被分片
mds->balancer->maybe_fragment(dir, false);
}
由于时间问题,文章还在努力完善中…