return true;
}
-
-/** validate_dentry_dir
- *
- * verify that the dir exists and would own the dname.
- * do not check if the dentry exists.
- */
-CDir *Server::validate_dentry_dir(MDRequestRef& mdr, CInode *diri, std::string_view dname)
-{
- // make sure parent is a dir?
- if (!diri->is_dir()) {
- dout(7) << "validate_dentry_dir: not a dir" << dendl;
- respond_to_request(mdr, -ENOTDIR);
- return NULL;
- }
-
- // which dirfrag?
- frag_t fg = diri->pick_dirfrag(dname);
- CDir *dir = try_open_auth_dirfrag(diri, fg, mdr);
- if (!dir)
- return 0;
-
- // frozen?
- if (dir->is_frozen()) {
- dout(7) << "dir is frozen " << *dir << dendl;
- dir->add_waiter(CDir::WAIT_UNFREEZE, new C_MDS_RetryRequest(mdcache, mdr));
- return NULL;
- }
-
- return dir;
-}
-
-
-/** prepare_null_dentry
- * prepare a null (or existing) dentry in given dir.
- * wait for any dn lock.
- */
-CDentry* Server::prepare_null_dentry(MDRequestRef& mdr, CDir *dir, std::string_view dname, bool okexist)
-{
- dout(10) << "prepare_null_dentry " << dname << " in " << *dir << dendl;
- ceph_assert(dir->is_auth());
-
- client_t client = mdr->get_client();
-
- // does it already exist?
- CDentry *dn = dir->lookup(dname);
- if (dn) {
- /*
- if (dn->lock.is_xlocked_by_other(mdr)) {
- dout(10) << "waiting on xlocked dentry " << *dn << dendl;
- dn->lock.add_waiter(SimpleLock::WAIT_RD, new C_MDS_RetryRequest(mdcache, mdr));
- return 0;
- }
- */
- if (!dn->get_linkage(client, mdr)->is_null()) {
- // name already exists
- dout(10) << "dentry " << dname << " exists in " << *dir << dendl;
- if (!okexist) {
- respond_to_request(mdr, -EEXIST);
- return 0;
- }
- } else {
- snapid_t next_snap = mdcache->get_global_snaprealm()->get_newest_seq() + 1;
- dn->first = std::max(dn->first, next_snap);
- }
- return dn;
- }
-
- // make sure dir is complete
- if (!dir->is_complete() && (!dir->has_bloom() || dir->is_in_bloom(dname))) {
- dout(7) << " incomplete dir contents for " << *dir << ", fetching" << dendl;
- dir->fetch(new C_MDS_RetryRequest(mdcache, mdr));
- return 0;
- }
-
- // create
- dn = dir->add_null_dentry(dname, mdcache->get_global_snaprealm()->get_newest_seq() + 1);
- dn->mark_new();
- dout(10) << "prepare_null_dentry added " << *dn << dendl;
- return dn;
-}
-
CDentry* Server::prepare_stray_dentry(MDRequestRef& mdr, CInode *in)
{
CDentry *straydn = mdr->straydn;
MDRequestRef mdr;
};
-CDir *Server::traverse_to_auth_dir(MDRequestRef& mdr, vector<CDentry*> &trace, filepath refpath)
-{
- // figure parent dir vs dname
- if (refpath.depth() == 0) {
- dout(7) << "can't do that to root" << dendl;
- respond_to_request(mdr, -EINVAL);
- return 0;
- }
- string dname = refpath.last_dentry();
- refpath.pop_dentry();
-
- dout(10) << "traverse_to_auth_dir dirpath " << refpath << " dname " << dname << dendl;
-
- // traverse to parent dir
- CInode *diri;
- CF_MDS_MDRContextFactory cf(mdcache, mdr);
- int r = mdcache->path_traverse(mdr, cf, refpath, 0, &trace, &diri);
- if (r > 0) return 0; // delayed
- if (r < 0) {
- if (r == -ESTALE) {
- dout(10) << "FAIL on ESTALE but attempting recovery" << dendl;
- mdcache->find_ino_peers(refpath.get_ino(), new C_MDS_TryFindInode(this, mdr));
- return 0;
- }
- respond_to_request(mdr, r);
- return 0;
- }
-
- // is it an auth dir?
- CDir *dir = validate_dentry_dir(mdr, diri, dname);
- if (!dir)
- return 0; // forwarded or waiting for freeze
-
- dout(10) << "traverse_to_auth_dir " << *dir << dendl;
- return dir;
-}
-
/* If this returns null, the request has been handled
* as appropriate: forwarded on, or the client's been replied to */
CInode* Server::rdlock_path_pin_ref(MDRequestRef& mdr, int n,
if (mdr->done_locking)
return mdr->in[n];
+ if (!no_want_auth && refpath.is_last_snap())
+ want_auth = true;
+
// traverse
CF_MDS_MDRContextFactory cf(mdcache, mdr);
- int r = mdcache->path_traverse(mdr, cf, refpath, 0, &mdr->dn[n], &mdr->in[n]);
+ int flags = 0;
+ if (want_auth)
+ flags |= MDS_TRAVERSE_WANT_AUTH;
+ int r = mdcache->path_traverse(mdr, cf, refpath, flags, &mdr->dn[n], &mdr->in[n]);
if (r > 0)
- return NULL; // delayed
+ return nullptr; // delayed
if (r < 0) { // error
if (r == -ENOENT && n == 0 && !mdr->dn[n].empty()) {
if (!no_lookup) {
CInode *ref = mdr->in[n];
dout(10) << "ref is " << *ref << dendl;
- // fw to inode auth?
- if (mdr->snapid != CEPH_NOSNAP && !no_want_auth)
- want_auth = true;
-
if (want_auth) {
- if (ref->is_ambiguous_auth()) {
- dout(10) << "waiting for single auth on " << *ref << dendl;
- ref->add_waiter(CInode::WAIT_SINGLEAUTH, new C_MDS_RetryRequest(mdcache, mdr));
- return 0;
- }
- if (!ref->is_auth()) {
- dout(10) << "fw to auth for " << *ref << dendl;
- mdcache->request_forward(mdr, ref->authority().first);
- return 0;
- }
-
// auth_pin?
// do NOT proceed if freezing, as cap release may defer in that case, and
// we could deadlock when we try to lock @ref.
*/
CDentry* Server::rdlock_path_xlock_dentry(MDRequestRef& mdr, int n,
MutationImpl::LockOpVec& lov,
- bool okexist, bool mustexist, bool alwaysxlock,
+ bool okexist, bool alwaysxlock,
file_layout_t **layout)
{
const filepath& refpath = n ? mdr->get_filepath2() : mdr->get_filepath();
dout(10) << "rdlock_path_xlock_dentry " << *mdr << " " << refpath << dendl;
-
- client_t client = mdr->get_client();
-
if (mdr->done_locking)
return mdr->dn[n].back();
- CDir *dir = traverse_to_auth_dir(mdr, mdr->dn[n], refpath);
- if (!dir) return 0;
+ CF_MDS_MDRContextFactory cf(mdcache, mdr);
+ int flags = MDS_TRAVERSE_WANT_DENTRY | MDS_TRAVERSE_WANT_AUTH;
+ int r = mdcache->path_traverse(mdr, cf, refpath, flags, &mdr->dn[n]);
+ if (r > 0)
+ return nullptr; // delayed
+ if (r < 0) {
+ if (r == -ESTALE) {
+ dout(10) << "FAIL on ESTALE but attempting recovery" << dendl;
+ mdcache->find_ino_peers(refpath.get_ino(), new C_MDS_TryFindInode(this, mdr));
+ return nullptr;
+ }
+ respond_to_request(mdr, r);
+ return nullptr;
+ }
+ CDentry *dn = mdr->dn[0].back();
+ CDir *dir = dn->get_dir();
CInode *diri = dir->get_inode();
+
if (!mdr->reqid.name.is_mds()) {
if (diri->is_system() && !diri->is_root()) {
respond_to_request(mdr, -EROFS);
return 0;
}
}
+
if (!diri->is_base() && diri->get_projected_parent_dir()->inode->is_stray()) {
respond_to_request(mdr, -ENOENT);
return 0;
}
- // make a null dentry?
- std::string_view dname = refpath.last_dentry();
- CDentry *dn;
- if (mustexist) {
- dn = dir->lookup(dname);
-
- // make sure dir is complete
- if (!dn && !dir->is_complete() &&
- (!dir->has_bloom() || dir->is_in_bloom(dname))) {
- dout(7) << " incomplete dir contents for " << *dir << ", fetching" << dendl;
- dir->fetch(new C_MDS_RetryRequest(mdcache, mdr));
- return 0;
- }
+ client_t client = mdr->get_client();
+ if (dn && !dn->lock.can_read(client) && dn->lock.get_xlock_by() != mdr) {
+ dout(10) << "waiting on xlocked dentry " << *dn << dendl;
+ dn->lock.add_waiter(SimpleLock::WAIT_RD, new C_MDS_RetryRequest(mdcache, mdr));
+ return 0;
+ }
- // readable?
- if (dn && !dn->lock.can_read(client) && dn->lock.get_xlock_by() != mdr) {
- dout(10) << "waiting on xlocked dentry " << *dn << dendl;
- dn->lock.add_waiter(SimpleLock::WAIT_RD, new C_MDS_RetryRequest(mdcache, mdr));
+ CDentry::linkage_t *dnl = dn->get_linkage(client, mdr);
+ if (!dnl->is_null()) {
+ // name already exists
+ dout(10) << "dentry " << dn->get_name() << " exists in " << *dir << dendl;
+ if (!okexist) {
+ respond_to_request(mdr, -EEXIST);
return 0;
}
-
- // exists?
- if (!dn || dn->get_linkage(client, mdr)->is_null()) {
- dout(7) << "dentry " << dname << " dne in " << *dir << dendl;
- respond_to_request(mdr, -ENOENT);
- return 0;
- }
} else {
- dn = prepare_null_dentry(mdr, dir, dname, okexist);
- if (!dn)
- return 0;
+ snapid_t next_snap = mdcache->get_global_snaprealm()->get_newest_seq() + 1;
+ dn->first = std::max(dn->first, next_snap);
}
-
- mdr->dn[n].push_back(dn);
- CDentry::linkage_t *dnl = dn->get_linkage(client, mdr);
mdr->in[n] = dnl->get_inode();
// -- lock --
MutationImpl::LockOpVec lov;
file_layout_t *dir_layout = nullptr;
CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, lov,
- !excl, false, false, &dir_layout);
+ !excl, false, &dir_layout);
if (!dn) return;
if (mdr->snapid != CEPH_NOSNAP) {
respond_to_request(mdr, -EROFS);
client_t client = mdr->get_client();
MutationImpl::LockOpVec lov;
file_layout_t *dir_layout = nullptr;
- CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, lov, false, false, false,
+ CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, lov, false, false,
&dir_layout);
if (!dn) return;
if (mdr->snapid != CEPH_NOSNAP) {
}
MutationImpl::LockOpVec lov;
- CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, lov, false, false, false);
+ CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, lov, false, false);
if (!dn) return;
if (mdr->snapid != CEPH_NOSNAP) {
respond_to_request(mdr, -EROFS);
{
const cref_t<MClientRequest> &req = mdr->client_request;
MutationImpl::LockOpVec lov;
- CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, lov, false, false, false);
+ CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, lov, false, false);
if (!dn) return;
if (mdr->snapid != CEPH_NOSNAP) {
respond_to_request(mdr, -EROFS);
MutationImpl::LockOpVec lov;
- CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, lov, false, false, false);
+ CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, lov, false, false);
if (!dn) return;
CInode *targeti = rdlock_path_pin_ref(mdr, 1, lov, false);
if (!targeti) return;
MutationImpl::LockOpVec lov;
- CDentry *destdn = rdlock_path_xlock_dentry(mdr, 0, lov, true, false, true);
+ CDentry *destdn = rdlock_path_xlock_dentry(mdr, 0, lov, true, true);
if (!destdn) return;
dout(10) << " destdn " << *destdn << dendl;
if (mdr->snapid != CEPH_NOSNAP) {