unsigned char remote_d_type;
CInode *inode; // linked inode (if any)
+ CInode *projected_inode; // projected inode (if any)
CDir *dir; // containing dirfrag
version_t version; // dir version when last touched.
name(n),
first(f), last(l),
remote_ino(0), remote_d_type(0),
- inode(0), dir(0),
+ inode(0), projected_inode(0), dir(0),
version(0), projected_version(0),
xlist_dirty(this),
auth_pins(0), nested_auth_pins(0), nested_anchors(0),
name(n),
first(f), last(l),
remote_ino(ino), remote_d_type(dt),
- inode(0), dir(0),
+ inode(0), projected_inode(0), dir(0),
version(0), projected_version(0),
xlist_dirty(this),
auth_pins(0), nested_auth_pins(0), nested_anchors(0),
{
assert(dn->inode == 0);
dn->inode = in;
+ dn->projected_inode = 0;
in->set_primary_parent(dn);
if (dn->last == CEPH_NOSNAP)
while (!cur->snaprealm) {
if (cur->get_parent_dn())
cur = cur->get_parent_dn()->get_dir()->get_inode();
- else if (cur == this && get_projected_parent_dn())
- cur = get_projected_parent_dn()->get_dir()->get_inode();
+ else if (get_projected_parent_dn())
+ cur = cur->get_projected_parent_dn()->get_dir()->get_inode();
else
break;
}
vector<CDentry*>& trace, // result
snapid_t *psnapid, CInode **psnapdiri,
bool follow_trailing_symlink, // how
- int onfail)
+ int onfail,
+ bool allow_projected)
{
assert(mdr || req);
bool null_okay = (onfail == MDS_TRAVERSE_DISCOVERXLOCK);
if (psnapdiri)
*psnapdiri = 0;
+ int client = mdr->reqid.name.is_client() ? mdr->reqid.name.num() : -1;
+
// root
CInode *cur = get_inode(origpath.get_ino());
if (cur == NULL) {
// dentry
CDentry *dn = curdir->lookup(path[depth], snapid);
+ bool use_projected = false;
+ if (allow_projected &&
+ dn &&
+ dn->is_null() &&
+ dn->lock.is_xlocked() &&
+ dn->lock.can_rdlock(mdr, client) &&
+ dn->projected_inode)
+ use_projected = true;
+
// null and last_bit and xlocked by me?
if (dn && dn->is_null()) {
if (null_okay) {
trace.push_back(dn);
break; // done!
}
- if (dn->lock.is_xlocked() && dn->lock.get_xlocked_by() != mdr) {
+ if (dn->lock.is_xlocked() &&
+ dn->lock.get_xlocked_by() != mdr &&
+ !use_projected) {
dout(10) << "traverse: xlocked null dentry at " << *dn << dendl;
dn->lock.add_waiter(SimpleLock::WAIT_RD, _get_waiter(mdr, req));
if (mds->logger) mds->logger->inc("tlock");
}
- if (dn && !dn->is_null()) {
+ if (dn && (!dn->is_null() || use_projected)) {
// dentry exists. xlocked?
- if (!noperm && dn->lock.is_xlocked() && dn->lock.get_xlocked_by() != mdr) {
+ if (!noperm &&
+ dn->lock.is_xlocked() &&
+ dn->lock.get_xlocked_by() != mdr &&
+ !dn->lock.can_rdlock(mdr, client)) {
dout(10) << "traverse: xlocked dentry at " << *dn << dendl;
dn->lock.add_waiter(SimpleLock::WAIT_RD, _get_waiter(mdr, req));
if (mds->logger) mds->logger->inc("tlock");
return 1;
}
+ CInode *in = use_projected ? dn->projected_inode : dn->inode;
+
// do we have inode?
- if (!dn->inode) {
+ if (!in) {
assert(dn->is_remote());
// do i have it?
- CInode *in = get_inode(dn->get_remote_ino());
+ in = get_inode(dn->get_remote_ino());
if (in) {
dout(7) << "linking in remote in " << *in << dendl;
dn->link_remote(in);
}
// symlink?
- if (dn->inode->is_symlink() &&
+ if (in->is_symlink() &&
(follow_trailing_symlink || depth < path.depth()-1)) {
// symlink, resolve!
- filepath sym = dn->inode->symlink;
- dout(10) << "traverse: hit symlink " << *dn->inode << " to " << sym << dendl;
+ filepath sym = in->symlink;
+ dout(10) << "traverse: hit symlink " << *in << " to " << sym << dendl;
// break up path components
// /head/symlink/tail
dout(10) << "traverse: path head = " << head << dendl;
dout(10) << "traverse: path tail = " << tail << dendl;
- if (symlinks_resolved.count(pair<CInode*,string>(dn->inode, tail.get_path()))) {
+ if (symlinks_resolved.count(pair<CInode*,string>(in, tail.get_path()))) {
dout(10) << "already hit this symlink, bailing to avoid the loop" << dendl;
return -ELOOP;
}
- symlinks_resolved.insert(pair<CInode*,string>(dn->inode, tail.get_path()));
+ symlinks_resolved.insert(pair<CInode*,string>(in, tail.get_path()));
// start at root?
- if (dn->inode->symlink[0] == '/') {
+ if (in->symlink[0] == '/') {
// absolute
trace.clear();
depth = 0;
- path = dn->inode->symlink;
+ path = in->symlink;
path.append(tail);
dout(10) << "traverse: absolute symlink, path now " << path << " depth " << depth << dendl;
} else {
reply->starts_with = MDiscoverReply::DENTRY;
replicate_dentry(dn, from, reply->trace);
if (dn->is_primary())
- replicate_inode(dn->inode, from, reply->trace);
+ replicate_inode(in, from, reply->trace);
mds->send_message_mds(reply, req->get_source().num());
}
}
// add to trace, continue.
trace.push_back(dn);
- cur = dn->inode;
+ cur = in;
touch_inode(cur);
depth++;
continue;
*
* will return inode for primary, or link up/open up remote link's inode as necessary.
*/
-CInode *MDCache::get_dentry_inode(CDentry *dn, MDRequest *mdr)
+CInode *MDCache::get_dentry_inode(CDentry *dn, MDRequest *mdr, bool projected)
{
+ if (projected && dn->projected_inode)
+ return dn->projected_inode;
+
assert(!dn->is_null());
- if (dn->is_primary())
+ if (dn->is_primary())
return dn->inode;
assert(dn->is_remote());
int path_traverse(MDRequest *mdr, Message *req, filepath& path,
vector<CDentry*>& trace, snapid_t *psnap, CInode **psnapdiri,
bool follow_trailing_sym,
- int onfail);
+ int onfail,
+ bool allow_projected=false);
bool path_is_mine(filepath& path);
bool path_is_mine(string& p) {
filepath path(p);
int inopath_traverse(MDRequest *mdr, vector<ceph_inopath_item>& inopath);
void open_remote_dirfrag(CInode *diri, frag_t fg, Context *fin);
- CInode *get_dentry_inode(CDentry *dn, MDRequest *mdr);
+ CInode *get_dentry_inode(CDentry *dn, MDRequest *mdr, bool projected=false);
void open_remote_ino(inodeno_t ino, Context *fin, inodeno_t hadino=0, version_t hadv=0);
void open_remote_ino_2(inodeno_t ino,
vector<Anchor>& anchortrace,
snapid_t snapid = CEPH_NOSNAP;
CInode *snapdiri = 0;
if (tracei || tracedn)
- set_trace_dist(mdr->session, reply, tracei, tracedn, snapid, snapdiri, true);
+ set_trace_dist(mdr->session, reply, tracei, tracedn, snapid, snapdiri, true, mdr);
mdr->did_early_reply = true;
*/
void Server::set_trace_dist(Session *session, MClientReply *reply, CInode *in, CDentry *dn,
snapid_t snapid, CInode *snapdiri,
- bool projected)
+ bool projected, MDRequest *mdr)
{
// inode, dentry, dir, ..., inode
bufferlist bl;
}
if (!dn) {
- if (projected)
+ if (projected && mdr) {
dn = in->get_projected_parent_dn();
- else
+ if (dn && mdr->locks.count(&dn->lock) == 0) // only use projected value if we've locked it!
+ dn = NULL;
+ }
+ if (!dn)
dn = in->get_parent_dn();
}
if (!dn)
goto done;
dentry:
- projected = false;
-
::encode(dn->get_name(), bl);
if (snapid == CEPH_NOSNAP)
lmask = mds->locker->issue_client_lease(dn, client, bl, now, session);
snapid_t snapid;
int r = mdcache->path_traverse(mdr, mdr->client_request,
refpath, trace, &snapid, &mdr->ref_snapdiri,
- false, MDS_TRAVERSE_FORWARD);
+ false, MDS_TRAVERSE_FORWARD,
+ true);
if (r > 0) return 0; // delayed
if (r < 0) {
reply_request(mdr, r);
if (trace.empty())
diri = mdcache->get_inode(refpath.get_ino());
else
- diri = mdcache->get_dentry_inode(trace[trace.size()-1], mdr);
+ diri = mdcache->get_dentry_inode(trace[trace.size()-1], mdr, true);
if (!diri)
return 0; // opening inode.
int r = mdcache->path_traverse(mdr, req,
refpath,
trace, &mdr->ref_snapid, &mdr->ref_snapdiri,
- req->follow_trailing_symlink(), MDS_TRAVERSE_FORWARD);
+ req->follow_trailing_symlink(), MDS_TRAVERSE_FORWARD,
+ true);
if (r > 0) return false; // delayed
if (r < 0) { // error
reply_request(mdr, r);
}
// open ref inode
- ref = mdcache->get_dentry_inode(dn, mdr);
+ ref = mdcache->get_dentry_inode(dn, mdr, true);
if (!ref) return 0;
}
dout(10) << "ref is " << *ref << dendl;
assert(newi);
newi->projected_parent = dn;
+ dn->projected_inode = newi;
+
newi->inode.rdev = req->head.args.mknod.rdev;
newi->inode.mode = req->head.args.mknod.mode;
if ((newi->inode.mode & S_IFMT) == 0)
newi->inode.version = dn->pre_dirty() - 1;
newi->inode.rstat.rfiles = 1;
- newi->projected_parent = dn;
dn->first = newi->first = follows+1;
dout(10) << "mknod mode " << newi->inode.mode << " rdev " << newi->inode.rdev << dendl;
// it's a directory.
newi->projected_parent = dn;
+ dn->projected_inode = newi;
+
newi->inode.mode = req->head.args.mkdir.mode;
newi->inode.mode &= ~S_IFMT;
newi->inode.mode |= S_IFDIR;
// it's a symlink
newi->projected_parent = dn;
+ dn->projected_inode = newi;
+
newi->inode.mode &= ~S_IFMT;
newi->inode.mode |= S_IFLNK;
newi->inode.mode |= 0777; // ?
vector<CDentry*> targettrace;
int r = mdcache->path_traverse(mdr, req,
targetpath, targettrace, NULL, NULL,
- false, MDS_TRAVERSE_DISCOVER);
+ false, MDS_TRAVERSE_DISCOVER, true);
if (r > 0) return; // wait
if (targettrace.empty()) r = -EINVAL;
if (r < 0) {
}
// identify target inode
- CInode *targeti = targettrace[targettrace.size()-1]->inode;
- assert(targeti);
+ CInode *targeti = mdcache->get_dentry_inode(targettrace[targettrace.size()-1], mdr, true);
+ if (!targeti)
+ return;
// dir?
dout(7) << "target is " << *targeti << dendl;
// get/open inode.
mdr->trace.swap(trace);
- CInode *in = mdcache->get_dentry_inode(dn, mdr);
+ CInode *in = mdcache->get_dentry_inode(dn, mdr, true);
if (!in) return;
dout(7) << "dn links to " << *in << dendl;
pi->version = mdr->more()->pvmap[destdn] = destdn->pre_dirty(oldpv);
}
srcdn->inode->projected_parent = destdn;
+ destdn->projected_inode = srcdn->inode;
}
// src
// it's a file.
in->projected_parent = dn;
+ dn->projected_inode = in;
+
in->inode.mode = req->head.args.open.mode;
in->inode.mode |= S_IFREG;
in->inode.version = dn->pre_dirty() - 1;
void reply_request(MDRequest *mdr, MClientReply *reply, CInode *tracei = 0, CDentry *tracedn = 0);
void set_trace_dist(Session *session, MClientReply *reply, CInode *in, CDentry *dn,
snapid_t snapid, CInode *snapdiri,
- bool projected = false);
+ bool projected = false, MDRequest *mdr = 0);
void encode_empty_dirstat(bufferlist& bl);
void encode_infinite_lease(bufferlist& bl);