bool discover = (flags & MDS_TRAVERSE_DISCOVER);
bool forward = !discover;
bool last_xlocked = (flags & MDS_TRAVERSE_LAST_XLOCKED);
+ bool want_dentry = (flags & MDS_TRAVERSE_WANT_DENTRY);
if (forward)
ceph_assert(mdr); // forward requires a request
CDentry::linkage_t *dnl = dn->get_projected_linkage();
// can we conclude ENOENT?
if (dnl->is_null()) {
- if (pin)
- *pin = nullptr;
-
+ dout(10) << "traverse: null+readable dentry at " << *dn << dendl;
if (depth == path.depth() - 1) {
- if (last_xlocked) {
- dout(10) << "traverse: null+tail+xlocked dentry at " << *dn << dendl;
+ if (want_dentry)
break;
- }
} else {
if (pdnvec)
pdnvec->clear(); // do not confuse likes of rdlock_path_pin_ref();
}
- dout(10) << "traverse: null+readable dentry at " << *dn << dendl;
return -ENOENT;
}
continue;
}
+ ceph_assert(!dn);
+
// MISS. dentry doesn't exist.
dout(12) << "traverse: miss on dentry " << path[depth] << " in " << *curdir << dendl;
// file not found
if (pdnvec) {
// instantiate a null dn?
- if (depth < path.depth()-1){
+ if (depth < path.depth() - 1) {
dout(20) << " didn't traverse full path; not returning pdnvec" << dendl;
- dn = NULL;
- } else if (dn) {
- ceph_abort(); // should have fallen out in ->is_null() check above
- } else if (curdir->is_frozen()) {
- dout(20) << " not adding null to frozen dir " << dendl;
} else if (snapid < CEPH_MAXSNAP) {
dout(20) << " not adding null for snapid " << snapid << dendl;
+ } else if (curdir->is_frozen()) {
+ dout(7) << "traverse: " << *curdir << " is frozen, waiting" << dendl;
+ curdir->add_waiter(CDir::WAIT_UNFREEZE, cf.build());
+ return 1;
} else {
// create a null dentry
dn = curdir->add_null_dentry(path[depth]);
dout(20) << " added null " << *dn << dendl;
}
- if (dn)
+ if (dn) {
pdnvec->push_back(dn);
- else
+ if (want_dentry)
+ break;
+ } else {
pdnvec->clear(); // do not confuse likes of rdlock_path_pin_ref();
+ }
}
return -ENOENT;
} else {
// flags for path_traverse();
static const int MDS_TRAVERSE_DISCOVER = (1 << 0);
static const int MDS_TRAVERSE_LAST_XLOCKED = (1 << 1);
+static const int MDS_TRAVERSE_WANT_DENTRY = (1 << 2);
// flags for predirty_journal_parents()
static const int PREDIRTY_PRIMARY = 1; // primary dn, adjust nested accounting
* MDS_TRAVERSE_DISCOVER: Instead of forwarding request, path_traverse()
* attempts to look up the path from a different MDS (and bring them into
* its cache as replicas).
- * MDS_TRAVERSE_LAST_XLOCKED: path_traverse() will succeed on xlocked tail
- * dentry (return 0 even it's null).
+ * MDS_TRAVERSE_LAST_XLOCKED: path_traverse() will procceed when xlocked tail
+ * dentry is encountered.
+ * MDS_TRAVERSE_WANT_DENTRY: Caller wants tail dentry. Add a null dentry if
+ * tail dentry does not exist. return 0 even tail dentry is null.
*
* @param pdnvec Data return parameter -- on success, contains a
* vector of dentries. On failure, is either empty or contains the
vector<CDentry*> trace;
CF_MDS_MDRContextFactory cf(mdcache, mdr);
int r = mdcache->path_traverse(mdr, cf, destpath,
- MDS_TRAVERSE_DISCOVER | MDS_TRAVERSE_LAST_XLOCKED,
+ MDS_TRAVERSE_DISCOVER | MDS_TRAVERSE_LAST_XLOCKED | MDS_TRAVERSE_WANT_DENTRY,
&trace);
if (r > 0) return;
if (r == -ESTALE) {
if (r > 0) return;
ceph_assert(r == 0);
- // srcpath must not point to a null dentry
- ceph_assert(srci != nullptr);
-
CDentry *srcdn = trace.back();
CDentry::linkage_t *srcdnl = srcdn->get_projected_linkage();
dout(10) << " srcdn " << *srcdn << dendl;