<< " cap_refs=" << in.cap_refs
<< " open=" << in.open_by_mode
<< " ref=" << in.ref
+ << " parent=" << in.dn
<< ")";
return out;
}
}
__u16 numi, numd;
+ __s16 snapdirpos;
::decode(numi, p);
::decode(numd, p);
- dout(10) << "insert_trace got " << numi << " inodes, " << numd << " dentries" << dendl;
+ ::decode(snapdirpos, p);
+ dout(10) << "insert_trace got " << numi << " inodes, " << numd << " dentries, snapdir at " << snapdirpos << dendl;
+ int icount = 0;
// decode
- LeaseStat ilease[numi];
- InodeStat ist[numi];
+ LeaseStat ilease[numi], snapdirlease;
+ InodeStat ist[numi], snapdirst;
DirStat dst[numd];
string dname[numd];
LeaseStat dlease[numd];
inode:
if (!ileft) goto done;
- ileft--;
+ ileft--; icount++;
+ if (icount == snapdirpos) {
+ snapdirst.decode(p);
+ ::decode(snapdirlease, p);
+ }
ist[ileft].decode(p);
::decode(ilease[ileft], p);
curi = inode_map[vino];
}
update_inode(curi, &ist[0], &ilease[0], from);
+ dout(10) << " (base) curi " << *curi << dendl;
for (unsigned i=0; i<numd; i++) {
Dir *dir = curi->open_dir();
}
curi = insert_dentry_inode(dir, dname[i], &dlease[i], &ist[i+1], &ilease[i+1], from);
+ dout(10) << " curi " << *curi << dendl;
+
+ if ((int)i == numi-snapdirpos-1) {
+ Inode *snapdiri = open_snapdir(curi);
+ dout(10) << " snapdir " << *snapdiri << dendl;
+ char s[20];
+ sprintf(s, "%llu", (unsigned long long)snapdirst.vino.snapid);
+ string snapname = s;
+ Dir *snapdir = snapdiri->open_dir();
+ curi = insert_dentry_inode(snapdir, snapname, &snapdirlease, // FIXME
+ &snapdirst, &snapdirlease, from);
+ dout(10) << " snapped diri " << *curi << dendl;
+ }
+
update_dir_dist(curi, &dst[i]); // dir stat info is attached to inode...
}
assert(p.end());
dout(10) << "_readdir_get_frag " << dirp << " on " << dirp->path << " fg " << fg << dendl;
int op = CEPH_MDS_OP_READDIR;
- if (dirp->inode && dirp->inode->snapid == SNAPDIR)
+ if (dirp->inode && dirp->inode->snapid == CEPH_SNAPDIR)
op = CEPH_MDS_OP_LSSNAP;
MClientRequest *req = new MClientRequest(op);
#define FUSE_SET_ATTR_ATIME (1 << 4)
#define FUSE_SET_ATTR_MTIME (1 << 5)
+
+Inode *Client::open_snapdir(Inode *diri)
+{
+ Inode *in;
+ vinodeno_t vino(diri->ino(), CEPH_SNAPDIR);
+ if (!inode_map.count(vino)) {
+ in = new Inode(vino, &diri->inode.layout);
+ in->inode = diri->inode;
+ in->snapid = CEPH_SNAPDIR;
+ in->inode.mode = S_IFDIR | 0600;
+ in->dirfragtree.clear();
+ inode_map[vino] = in;
+ in->snapdir_parent = diri;
+ diri->get();
+ dout(10) << "open_snapdir created snapshot inode " << *in << dendl;
+ } else {
+ in = inode_map[vino];
+ dout(10) << "open_snapdir had snapshot inode " << *in << dendl;
+ }
+ return in;
+}
+
int Client::ll_lookup(vinodeno_t parent, const char *name, struct stat *attr, int uid, int gid)
{
Mutex::Locker lock(client_lock);
// .snapshot?
if (dname == g_conf.client_snapdir &&
diri->snapid == CEPH_NOSNAP) {
- vinodeno_t vino(parent.ino, SNAPDIR);
- if (!inode_map.count(vino)) {
- in = new Inode(vino, &diri->inode.layout);
- in->inode = diri->inode;
- in->snapid = SNAPDIR;
- in->inode.mode = S_IFDIR | 0600;
- in->dirfragtree.clear();
- inode_map[vino] = in;
- in->snapdir_parent = diri;
- diri->get();
- dout(10) << " created snapshot inode " << *in << dendl;
- } else {
- in = inode_map[vino];
- dout(10) << " had snapshot inode " << *in << dendl;
- }
+ in = open_snapdir(diri);
} else {
// get the inode
if (diri->dir &&
filepath path;
diri->make_path(path);
path.push_dentry(name);
- _do_lstat(path, 0, &in, uid, gid);
+ dout(10) << "ll_lookup on " << path << dendl;
+ //_do_lstat(path, 0, &in, uid, gid);
+ MClientRequest *req = new MClientRequest(CEPH_MDS_OP_LSTAT);
+ req->head.args.stat.mask = 0;
+ req->set_filepath(path);
+
+ MClientReply *reply = make_request(req, uid, gid, &in, 0);
+ r = reply->get_result();
+ dout(10) << "ll_lookup lstat res is " << r << dendl;
+ delete reply;
}
}
fill_stat(in, attr);
_ll_get(in);
} else {
- r = -ENOENT;
+ if (!r) r = -ENOENT;
attr->st_ino = 0;
}
assert(diri);
filepath path;
- if (vino.snapid == SNAPDIR) {
+ if (vino.snapid == CEPH_SNAPDIR) {
Inode *livediri = inode_map[vinodeno_t(vino.ino, CEPH_NOSNAP)];
assert(livediri);
livediri->make_path(path);
dout(10) << " ino path is " << path << dendl;
int r = 0;
- if (vino.snapid == SNAPDIR) {
+ if (vino.snapid == CEPH_SNAPDIR) {
*dirpp = new DirResult(path, diri);
} else {
r = _opendir(path.c_str(), (DirResult**)dirpp);
// infer tracei/tracedn from mdr?
+ snapid_t snapid = CEPH_NOSNAP;
+ CInode *snapdiri = 0;
if (!tracei && !tracedn && mdr->ref) {
tracei = mdr->ref;
+ snapdiri = mdr->ref_snapdiri;
+ snapid = mdr->ref_snapid;
dout(20) << "inferring tracei to be " << *tracei << dendl;
if (!mdr->trace.empty()) {
tracedn = mdr->trace.back();
} else {
// send reply, with trace, and possible leases
if (tracei || tracedn)
- set_trace_dist(session, reply, tracei, tracedn);
+ set_trace_dist(session, reply, tracei, tracedn, snapid, snapdiri);
messenger->send_message(reply, client_inst);
}
*
* trace is in reverse order (i.e. root inode comes last)
*/
-void Server::set_trace_dist(Session *session, MClientReply *reply, CInode *in, CDentry *dn)
+void Server::set_trace_dist(Session *session, MClientReply *reply, CInode *in, CDentry *dn,
+ snapid_t snapid, CInode *snapdiri)
{
// inode, dentry, dir, ..., inode
bufferlist bl;
int whoami = mds->get_nodeid();
int client = session->get_client();
__u16 numi = 0, numdn = 0;
+ __s16 snapdirpos = -1;
// choose lease duration
utime_t now = g_clock.now();
}
inode:
- in->encode_inodestat(bl);
- lmask = mds->locker->issue_client_lease(in, client, bl, now, session);
numi++;
- dout(20) << " trace added " << lmask << " " << *in << dendl;
+ in->encode_inodestat(bl, snapid);
+ lmask = mds->locker->issue_client_lease(in, client, bl, now, session);
+ dout(20) << " trace added " << lmask << " snapid " << snapid << " " << *in << dendl;
+
+ if (snapid != CEPH_NOSNAP && in == snapdiri) {
+ snapid = CEPH_NOSNAP;
+ snapdirpos = numi;
+ dout(10) << " snapdiri at pos " << snapdirpos << dendl;
+ in->encode_inodestat(bl, snapid);
+ lmask = mds->locker->issue_client_lease(in, client, bl, now, session);
+ dout(20) << " trace added " << lmask << " snapid " << snapid << " " << *in << dendl;
+ }
if (!dn)
dn = in->get_parent_dn();
::encode(dn->get_name(), bl);
lmask = mds->locker->issue_client_lease(dn, client, bl, now, session);
numdn++;
- dout(20) << " trace added " << lmask << " " << *dn << dendl;
+ dout(20) << " trace added " << lmask << " snapid " << snapid << " " << *dn << dendl;
// dir
#ifdef MDS_VERIFY_FRAGSTAT
bufferlist fbl;
::encode(numi, fbl);
::encode(numdn, fbl);
+ ::encode(snapdirpos, fbl);
fbl.claim_append(bl);
reply->set_trace(fbl);
}
// traverse to parent dir
snapid_t snapid;
int r = mdcache->path_traverse(mdr, mdr->client_request,
- refpath, trace, &snapid, false,
- MDS_TRAVERSE_FORWARD);
+ refpath, trace, &snapid, &mdr->ref_snapdiri,
+ false, MDS_TRAVERSE_FORWARD);
if (r > 0) return 0; // delayed
if (r < 0) {
reply_request(mdr, r);
-CInode* Server::rdlock_path_pin_ref(MDRequest *mdr, snapid_t *psnapid,
+CInode* Server::rdlock_path_pin_ref(MDRequest *mdr,
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, psnapid, req->follow_trailing_symlink(),
- MDS_TRAVERSE_FORWARD);
+ trace, &mdr->ref_snapid, &mdr->ref_snapdiri,
+ req->follow_trailing_symlink(), MDS_TRAVERSE_FORWARD);
if (r > 0) return false; // delayed
if (r < 0) { // error
reply_request(mdr, r);
{
MClientRequest *req = mdr->client_request;
int client = req->get_orig_source().num();
- snapid_t snapid;
- CInode *diri = rdlock_path_pin_ref(mdr, &snapid, false, true); // rdlock dirfragtreelock!
+ CInode *diri = rdlock_path_pin_ref(mdr, false, true); // rdlock dirfragtreelock!
if (!diri) return;
// it's a directory, right?
mdr->now = g_clock.real_now();
+ snapid_t snapid = mdr->ref_snapid;
+ dout(10) << "snapid " << snapid << dendl;
+
// build dir contents
bufferlist dirbl, dnbl;
dir->encode_dirstat(dirbl, mds->get_nodeid());
}
assert(in);
- dout(12) << "including inode " << *in << dendl;
-
// dentry
+ dout(12) << "including dn " << *dn << dendl;
::encode(dn->name, dnbl);
mds->locker->issue_client_lease(dn, client, dnbl, mdr->now, mdr->session);
// inode
+ dout(12) << "including inode " << *in << dendl;
in->encode_inodestat(dnbl);
mds->locker->issue_client_lease(in, client, dnbl, mdr->now, mdr->session);
numfiles++;
MDRequest *mdr;
CDentry *dn;
CInode *newi;
+ snapid_t follows;
public:
- C_MDS_mknod_finish(MDS *m, MDRequest *r, CDentry *d, CInode *ni) :
- mds(m), mdr(r), dn(d), newi(ni) {}
+ C_MDS_mknod_finish(MDS *m, MDRequest *r, CDentry *d, CInode *ni, snapid_t f) :
+ mds(m), mdr(r), dn(d), newi(ni), follows(f) {}
void finish(int r) {
assert(r == 0);
CDentry *dn = rdlock_path_xlock_dentry(mdr, false, false);
if (!dn) return;
+ snapid_t follows = dn->dir->inode->find_snaprealm()->get_latest_snap();
mdr->now = g_clock.real_now();
+
CInode *newi = prepare_new_inode(mdr, dn->dir);
assert(newi);
newi->inode.dirstat.rfiles = 1;
newi->projected_parent = dn;
-
+ dn->first = newi->first = follows+1;
+
dout(10) << "mknod mode " << newi->inode.mode << " rdev " << newi->inode.rdev << dendl;
// prepare finisher
EUpdate *le = new EUpdate(mdlog, "mknod");
le->metablob.add_client_req(req->get_reqid());
le->metablob.add_allocated_ino(newi->ino(), mds->idalloc->get_version());
-
+
mds->locker->predirty_nested(mdr, &le->metablob, newi, dn->dir, PREDIRTY_PRIMARY|PREDIRTY_DIR, 1);
- mdcache->journal_dirty_inode(&le->metablob, newi, dn->dir->inode->find_snaprealm()->get_latest_snap());
+ mdcache->journal_dirty_inode(&le->metablob, newi, follows);
// log + wait
- mdlog->submit_entry(le, new C_MDS_mknod_finish(mds, mdr, dn, newi));
+ mdlog->submit_entry(le, new C_MDS_mknod_finish(mds, mdr, dn, newi, follows));
}
if (!dn) return;
// new inode
+ snapid_t follows = dn->dir->inode->find_snaprealm()->get_latest_snap();
mdr->now = g_clock.real_now();
+
CInode *newi = prepare_new_inode(mdr, dn->dir);
assert(newi);
newi->inode.version = dn->pre_dirty() - 1;
newi->inode.dirstat.rsubdirs = 1;
+ dn->first = newi->first = follows+1;
+
// ...and that new dir is empty.
CDir *newdir = newi->get_or_open_dirfrag(mds->mdcache, frag_t());
newdir->mark_complete();
le->metablob.add_allocated_ino(newi->ino(), mds->idalloc->get_version());
mds->locker->predirty_nested(mdr, &le->metablob, newi, dn->dir, PREDIRTY_PRIMARY|PREDIRTY_DIR, 1);
//le->metablob.add_primary_dentry(dn, true, newi, &newi->inode);
- mdcache->journal_dirty_inode(&le->metablob, newi, dn->dir->inode->find_snaprealm()->get_latest_snap());
+ mdcache->journal_dirty_inode(&le->metablob, newi, follows);
le->metablob.add_dir(newdir, true, true); // dirty AND complete
// log + wait
- mdlog->submit_entry(le, new C_MDS_mknod_finish(mds, mdr, dn, newi));
+ mdlog->submit_entry(le, new C_MDS_mknod_finish(mds, mdr, dn, newi, follows));
}
if (!dn) return;
mdr->now = g_clock.real_now();
+ snapid_t follows = dn->dir->inode->find_snaprealm()->get_latest_snap();
CInode *newi = prepare_new_inode(mdr, dn->dir);
assert(newi);
newi->inode.version = dn->pre_dirty() - 1;
newi->inode.dirstat.rfiles = 1;
+ dn->first = newi->first = follows+1;
+
// prepare finisher
mdr->ls = mdlog->get_current_segment();
EUpdate *le = new EUpdate(mdlog, "symlink");
le->metablob.add_client_req(req->get_reqid());
le->metablob.add_allocated_ino(newi->ino(), mds->idalloc->get_version());
mds->locker->predirty_nested(mdr, &le->metablob, newi, dn->dir, PREDIRTY_PRIMARY|PREDIRTY_DIR, 1);
- mdcache->journal_dirty_inode(&le->metablob, newi, dn->dir->inode->find_snaprealm()->get_latest_snap());
+ mdcache->journal_dirty_inode(&le->metablob, newi, follows);
// log + wait
- mdlog->submit_entry(le, new C_MDS_mknod_finish(mds, mdr, dn, newi));
+ mdlog->submit_entry(le, new C_MDS_mknod_finish(mds, mdr, dn, newi, follows));
}
dout(7) << "handle_client_link discovering target " << targetpath << dendl;
vector<CDentry*> targettrace;
int r = mdcache->path_traverse(mdr, req,
- targetpath, targettrace, NULL, false,
- MDS_TRAVERSE_DISCOVER);
+ targetpath, targettrace, NULL, NULL,
+ false, MDS_TRAVERSE_DISCOVER);
if (r > 0) return; // wait
if (targettrace.empty()) r = -EINVAL;
if (r < 0) {
// traverse to path
vector<CDentry*> trace;
int r = mdcache->path_traverse(mdr, req,
- req->get_filepath(), trace, NULL, false,
- MDS_TRAVERSE_FORWARD);
+ req->get_filepath(), trace, NULL, NULL,
+ false, MDS_TRAVERSE_FORWARD);
if (r > 0) return;
if (trace.empty()) r = -EINVAL; // can't unlink root
if (r < 0) {
// traverse to src
vector<CDentry*> srctrace;
int r = mdcache->path_traverse(mdr, req,
- srcpath, srctrace, NULL, false,
- MDS_TRAVERSE_DISCOVER);
+ srcpath, srctrace, NULL, NULL,
+ false, MDS_TRAVERSE_DISCOVER);
if (r > 0) return;
if (r < 0) {
reply_request(mdr, r);
dout(10) << " dest " << destpath << dendl;
vector<CDentry*> trace;
int r = mdcache->path_traverse(mdr, mdr->slave_request,
- destpath, trace, NULL, false,
- MDS_TRAVERSE_DISCOVERXLOCK);
+ destpath, trace, NULL, 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, NULL, false,
- MDS_TRAVERSE_DISCOVERXLOCK);
+ srcpath, trace, NULL, NULL,
+ false, MDS_TRAVERSE_DISCOVERXLOCK);
if (r > 0) return;
assert(r == 0);
MDRequest *mdr;
CDentry *dn;
CInode *newi;
+ snapid_t follows;
public:
- C_MDS_openc_finish(MDS *m, MDRequest *r, CDentry *d, CInode *ni) :
- mds(m), mdr(r), dn(d), newi(ni) {}
+ C_MDS_openc_finish(MDS *m, MDRequest *r, CDentry *d, CInode *ni, snapid_t f) :
+ mds(m), mdr(r), dn(d), newi(ni), follows(f) {}
void finish(int r) {
assert(r == 0);
// create inode.
mdr->now = g_clock.real_now();
+ snapid_t follows = dn->dir->inode->find_snaprealm()->get_latest_snap();
+
CInode *in = prepare_new_inode(mdr, dn->dir);
assert(in);
in->inode.version = dn->pre_dirty() - 1;
in->inode.max_size = in->get_layout_size_increment();
in->inode.dirstat.rfiles = 1;
+
+ in->projected_parent = dn;
+ dn->first = in->first = follows+1;
// prepare finisher
mdr->ls = mdlog->get_current_segment();
le->metablob.add_client_req(req->get_reqid());
le->metablob.add_allocated_ino(in->ino(), mds->idalloc->get_version());
mds->locker->predirty_nested(mdr, &le->metablob, in, dn->dir, PREDIRTY_PRIMARY|PREDIRTY_DIR, 1);
- le->metablob.add_primary_dentry(dn, true, in, &in->inode);
+ mdcache->journal_dirty_inode(&le->metablob, in, follows);
// log + wait
- C_MDS_openc_finish *fin = new C_MDS_openc_finish(mds, mdr, dn, in);
+ C_MDS_openc_finish *fin = new C_MDS_openc_finish(mds, mdr, dn, in, follows);
mdlog->submit_entry(le, fin);
}
// traverse to path
vector<CDentry*> trace;
int r = mdcache->path_traverse(mdr, req,
- req->get_filepath(), trace, NULL, false,
- MDS_TRAVERSE_FORWARD);
+ req->get_filepath(), trace, NULL, NULL,
+ false, MDS_TRAVERSE_FORWARD);
if (r > 0) return;
if (trace.empty()) r = -EINVAL; // can't snap root
if (r < 0) {
// traverse to path
vector<CDentry*> trace;
int r = mdcache->path_traverse(mdr, req,
- req->get_filepath(), trace, NULL, false,
- MDS_TRAVERSE_FORWARD);
+ req->get_filepath(), trace, NULL, NULL,
+ false, MDS_TRAVERSE_FORWARD);
if (r > 0) return;
if (trace.empty()) r = -EINVAL; // can't snap root
if (r < 0) {