int MDCache::path_traverse(MDRequest *mdr, Message *req, // who
filepath& origpath, // what
vector<CDentry*>& trace, // result
+ snapid_t *psnapid,
bool follow_trailing_symlink, // how
int onfail)
{
// keep a list of symlinks we touch to avoid loops
set< pair<CInode*, string> > symlinks_resolved;
+ snapid_t snapid = CEPH_NOSNAP;
+
// root
CInode *cur = get_inode(origpath.get_ino());
if (cur == NULL) {
return -ENOTDIR;
}
+ // snapdir?
+ if (path[depth].length() == 0) {
+ dout(10) << "traverse: snapdir" << dendl;
+ snapid = CEPH_SNAPDIR;
+ depth++;
+ continue;
+ }
+ if (snapid == CEPH_SNAPDIR) {
+ snapid = atoll(path[depth].c_str());
+ dout(10) << "traverse: snap " << path[depth] << " -> " << snapid << dendl;
+ if (!snapid)
+ return -ENOENT;
+ SnapRealm *realm = cur->find_snaprealm();
+ if (realm->get_snaps().count(snapid) == 0)
+ return -ENOENT;
+ depth++;
+ continue;
+ }
+
// open dir
frag_t fg = cur->pick_dirfrag(path[depth]);
CDir *curdir = cur->get_dirfrag(fg);
// dentry
- CDentry *dn = curdir->lookup(path[depth]);
+ CDentry *dn = curdir->lookup(path[depth], snapid);
// null and last_bit and xlocked by me?
if (dn && dn->is_null() && null_okay) {
continue;
}
+
// MISS. dentry doesn't exist.
dout(12) << "traverse: miss on dentry " << path[depth] << " in " << *curdir << dendl;
}
// success.
+ if (psnapid)
+ *psnapid = CEPH_NOSNAP;
if (mds->logger) mds->logger->inc("thit");
return 0;
}
dout(5) << "trying discover on dir_update for " << path << dendl;
int r = path_traverse(0, m,
- path, trace, true,
+ path, trace, NULL, true,
MDS_TRAVERSE_DISCOVER);
if (r > 0)
return;
dout(10) << "traverse_to_auth_dir dirpath " << refpath << " dname " << dname << dendl;
// traverse to parent dir
+ snapid_t snapid;
int r = mdcache->path_traverse(mdr, mdr->client_request,
- refpath, trace, false,
+ refpath, trace, &snapid, false,
MDS_TRAVERSE_FORWARD);
if (r > 0) return 0; // delayed
if (r < 0) {
-CInode* Server::rdlock_path_pin_ref(MDRequest *mdr, bool want_auth, bool rdlock_dft)
+CInode* Server::rdlock_path_pin_ref(MDRequest *mdr, snapid_t *psnapid,
+ bool want_auth, bool rdlock_dft)
{
dout(10) << "rdlock_path_pin_ref " << *mdr << dendl;
vector<CDentry*> trace;
int r = mdcache->path_traverse(mdr, req,
refpath,
- trace, req->follow_trailing_symlink(),
+ trace, psnapid, req->follow_trailing_symlink(),
MDS_TRAVERSE_FORWARD);
if (r > 0) return false; // delayed
if (r < 0) { // error
void Server::handle_client_stat(MDRequest *mdr)
{
MClientRequest *req = mdr->client_request;
- CInode *ref = rdlock_path_pin_ref(mdr, false);
+ snapid_t snapid;
+ CInode *ref = rdlock_path_pin_ref(mdr, &snapid, false);
if (!ref) return;
// which inode locks do I want?
void Server::handle_client_utime(MDRequest *mdr)
{
MClientRequest *req = mdr->client_request;
- CInode *cur = rdlock_path_pin_ref(mdr, true);
+ snapid_t snapid;
+ CInode *cur = rdlock_path_pin_ref(mdr, &snapid, true);
__u32 mask;
if (!cur) return;
- if (cur->is_root()) {
+ if (snapid != CEPH_NOSNAP ||
+ cur->is_root()) {
reply_request(mdr, -EINVAL); // for now
return;
}
void Server::handle_client_chmod(MDRequest *mdr)
{
MClientRequest *req = mdr->client_request;
- CInode *cur = rdlock_path_pin_ref(mdr, true);
+ snapid_t snapid;
+ CInode *cur = rdlock_path_pin_ref(mdr, &snapid, true);
if (!cur) return;
- if (cur->is_root()) {
+ if (snapid != CEPH_NOSNAP ||
+ cur->is_root()) {
reply_request(mdr, -EINVAL); // for now
return;
}
void Server::handle_client_chown(MDRequest *mdr)
{
MClientRequest *req = mdr->client_request;
- CInode *cur = rdlock_path_pin_ref(mdr, true);
+ snapid_t snapid;
+ CInode *cur = rdlock_path_pin_ref(mdr, &snapid, true);
if (!cur) return;
- if (cur->is_root()) {
+ if (snapid != CEPH_NOSNAP || cur->is_root()) {
reply_request(mdr, -EINVAL); // for now
return;
}
void Server::handle_client_setxattr(MDRequest *mdr)
{
MClientRequest *req = mdr->client_request;
- CInode *cur = rdlock_path_pin_ref(mdr, true);
+ snapid_t snapid;
+ CInode *cur = rdlock_path_pin_ref(mdr, &snapid, true);
if (!cur) return;
- if (cur->is_root()) {
+ if (snapid != CEPH_NOSNAP || cur->is_root()) {
reply_request(mdr, -EINVAL); // for now
return;
}
void Server::handle_client_removexattr(MDRequest *mdr)
{
MClientRequest *req = mdr->client_request;
- CInode *cur = rdlock_path_pin_ref(mdr, true);
+ snapid_t snapid;
+ CInode *cur = rdlock_path_pin_ref(mdr, &snapid, true);
if (!cur) return;
- if (cur->is_root()) {
+ if (snapid != CEPH_NOSNAP || cur->is_root()) {
reply_request(mdr, -EINVAL); // for now
return;
}
{
MClientRequest *req = mdr->client_request;
int client = req->get_orig_source().num();
- CInode *diri = rdlock_path_pin_ref(mdr, false, true); // rdlock dirfragtreelock!
+ snapid_t snapid;
+ CInode *diri = rdlock_path_pin_ref(mdr, &snapid, false, true); // rdlock dirfragtreelock!
if (!diri) return;
// it's a directory, right?
it++) {
CDentry *dn = it->second;
if (dn->is_null()) continue;
+ if (dn->last < snapid || dn->first > snapid)
+ continue;
CInode *in = dn->inode;
dout(7) << "handle_client_link discovering target " << targetpath << dendl;
vector<CDentry*> targettrace;
int r = mdcache->path_traverse(mdr, req,
- targetpath, targettrace, false,
+ targetpath, targettrace, NULL, false,
MDS_TRAVERSE_DISCOVER);
if (r > 0) return; // wait
if (targettrace.empty()) r = -EINVAL;
// traverse to path
vector<CDentry*> trace;
int r = mdcache->path_traverse(mdr, req,
- req->get_filepath(), trace, false,
+ req->get_filepath(), trace, NULL, false,
MDS_TRAVERSE_FORWARD);
if (r > 0) return;
if (trace.empty()) r = -EINVAL; // can't unlink root
// traverse to src
vector<CDentry*> srctrace;
int r = mdcache->path_traverse(mdr, req,
- srcpath, srctrace, false,
+ srcpath, srctrace, NULL, false,
MDS_TRAVERSE_DISCOVER);
if (r > 0) return;
if (r < 0) {
dout(10) << " dest " << destpath << dendl;
vector<CDentry*> trace;
int r = mdcache->path_traverse(mdr, mdr->slave_request,
- destpath, trace, false,
+ destpath, trace, NULL, false,
MDS_TRAVERSE_DISCOVERXLOCK);
if (r > 0) return;
assert(r == 0); // we shouldn't get an error here!
filepath srcpath(mdr->slave_request->srcdnpath);
dout(10) << " src " << srcpath << dendl;
r = mdcache->path_traverse(mdr, mdr->slave_request,
- srcpath, trace, false,
+ srcpath, trace, NULL, false,
MDS_TRAVERSE_DISCOVERXLOCK);
if (r > 0) return;
assert(r == 0);
return;
}
- CInode *cur = rdlock_path_pin_ref(mdr, true);
+ snapid_t snapid;
+ CInode *cur = rdlock_path_pin_ref(mdr, &snapid, true);
if (!cur) return;
+ if (snapid != CEPH_NOSNAP) {
+ reply_request(mdr, -EINVAL);
+ return;
+ }
+
+
// check permissions?
// xlock inode
bool need_auth = !file_mode_is_readonly(cmode) || (flags & O_TRUNC);
dout(7) << "open on " << req->get_filepath() << dendl;
-
- CInode *cur = rdlock_path_pin_ref(mdr, need_auth);
+
+ snapid_t snapid;
+ CInode *cur = rdlock_path_pin_ref(mdr, &snapid, need_auth);
if (!cur) return;
// can only open a dir with mode FILE_MODE_PIN, at least for now.
// traverse to path
vector<CDentry*> trace;
int r = mdcache->path_traverse(mdr, req,
- req->get_filepath(), trace, false,
+ req->get_filepath(), trace, NULL, false,
MDS_TRAVERSE_FORWARD);
if (r > 0) return;
if (trace.empty()) r = -EINVAL; // can't snap root
// traverse to path
vector<CDentry*> trace;
int r = mdcache->path_traverse(mdr, req,
- req->get_filepath(), trace, false,
+ req->get_filepath(), trace, NULL, false,
MDS_TRAVERSE_FORWARD);
if (r > 0) return;
if (trace.empty()) r = -EINVAL; // can't snap root