From 1e5e8d8885fb9136e9c40b9ca1668f75e636f1c3 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 25 Aug 2009 14:56:23 -0700 Subject: [PATCH] mds: update dir parent pointer on rename Maintain per-segment list and inode flag for this purpose. Flush out changes on log segment trim. Also remove from renamed list if we commit first frag (which also writes a parent pointer each time). --- src/TODO | 8 -------- src/mds/CDir.cc | 25 +++++++++++++++++++------ src/mds/CDir.h | 2 +- src/mds/CInode.cc | 19 ++++++++++++++----- src/mds/CInode.h | 6 ++++-- src/mds/LogSegment.h | 1 + src/mds/Server.cc | 11 ++++++++++- src/mds/journal.cc | 9 +++++++++ src/mds/mdstypes.h | 9 +++++++-- 9 files changed, 65 insertions(+), 25 deletions(-) diff --git a/src/TODO b/src/TODO index 7aa9c88187cc2..494a9b5717c49 100644 --- a/src/TODO +++ b/src/TODO @@ -56,9 +56,6 @@ rados - security repair -- repair metadata.. -/ - parent pointer on CDir objects - - update on dir rename commit - namespace reconstruction tool - repair pg (rebuild log) (online or offline? ./cosd --repair_pg 1.ef?) - repair file ioctl? @@ -69,11 +66,6 @@ repair - data object - path backpointers? - parent dir pointer? -- cdir objects - - parent dir pointer - - update on rename? or on cdir store? - on cdir store is sufficient if mdlog survives... - - or what the hell, full trace? - mds scrubbing kclient diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index 5fef3e6846ee9..b491e979e51ec 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -1358,11 +1358,11 @@ public: class C_Dir_Committed : public Context { CDir *dir; - version_t version; + version_t version, last_renamed_version; public: - C_Dir_Committed(CDir *d, version_t v) : dir(d), version(v) { } + C_Dir_Committed(CDir *d, version_t v, version_t lrv) : dir(d), version(v), last_renamed_version(lrv) { } void finish(int r) { - dir->_committed(version); + dir->_committed(version, last_renamed_version); } }; @@ -1587,6 +1587,10 @@ void CDir::_commit(version_t want) _commit_partial(m, snaps); } + // update parent pointer while we're here. + // NOTE: the pointer is ONLY required to be valid for the first frag. we put the xattr + // on other frags too because it can't hurt, but it won't necessarily be up to date + // in that case!! inode->encode_parent_mutation(m); SnapContext snapc; @@ -1596,7 +1600,7 @@ void CDir::_commit(version_t want) cache->mds->mdsmap->get_metadata_pg_pool()); cache->mds->objecter->mutate(oid, ol, m, snapc, g_clock.now(), 0, - NULL, new C_Dir_Committed(this, get_version()) ); + NULL, new C_Dir_Committed(this, get_version(), inode->inode.last_renamed_version) ); } @@ -1605,10 +1609,19 @@ void CDir::_commit(version_t want) * * @param v version i just committed */ -void CDir::_committed(version_t v) +void CDir::_committed(version_t v, version_t lrv) { - dout(10) << "_committed v " << v << " on " << *this << dendl; + dout(10) << "_committed v " << v << " (last renamed " << lrv << ") on " << *this << dendl; assert(is_auth()); + + // did we update the parent pointer too? + if (get_frag() == frag_t() && // only counts on first frag + inode->state_test(CInode::STATE_DIRTYPARENT) && + lrv == inode->inode.last_renamed_version) { + inode->xlist_renamed_file.remove_myself(); + inode->state_clear(CInode::STATE_DIRTYPARENT); + dout(10) << "_committed stored parent pointer, removed from renamed_files list " << *inode << dendl; + } // take note. assert(v > committed_version); diff --git a/src/mds/CDir.h b/src/mds/CDir.h index 25ecc4d36c4d7..fb342e255086c 100644 --- a/src/mds/CDir.h +++ b/src/mds/CDir.h @@ -443,7 +443,7 @@ private: void _commit_full(ObjectOperation& m, const set *snaps); void _commit_partial(ObjectOperation& m, const set *snaps); void _encode_dentry(CDentry *dn, bufferlist& bl, const set *snaps); - void _committed(version_t v); + void _committed(version_t v, version_t last_renamed_version); void wait_for_commit(Context *c, version_t v=0); // -- dirtyness -- diff --git a/src/mds/CInode.cc b/src/mds/CInode.cc index 6bcdb09ae12c4..6ddbb59769f3a 100644 --- a/src/mds/CInode.cc +++ b/src/mds/CInode.cc @@ -101,6 +101,7 @@ ostream& operator<<(ostream& out, CInode& in) if (in.state_test(CInode::STATE_AMBIGUOUSAUTH)) out << " AMBIGAUTH"; if (in.state_test(CInode::STATE_NEEDSRECOVER)) out << " needsrecover"; if (in.state_test(CInode::STATE_RECOVERING)) out << " recovering"; + if (in.state_test(CInode::STATE_DIRTYPARENT)) out << " dirtyparent"; if (in.is_freezing_inode()) out << " FREEZING=" << in.auth_pin_freeze_allowance; if (in.is_frozen_inode()) out << " FROZEN"; @@ -736,10 +737,11 @@ void CInode::_fetched(bufferlist& bl, Context *fin) struct C_Inode_StoredParent : public Context { CInode *in; + version_t version; Context *fin; - C_Inode_StoredParent(CInode *i, Context *f) : in(i), fin(f) {} + C_Inode_StoredParent(CInode *i, version_t v, Context *f) : in(i), version(v), fin(f) {} void finish(int r) { - in->_stored_parent(fin); + in->_stored_parent(version, fin); } }; @@ -780,13 +782,20 @@ void CInode::store_parent(Context *fin) mdcache->mds->mdsmap->get_metadata_pg_pool()); mdcache->mds->objecter->mutate(oid, ol, m, snapc, g_clock.now(), 0, - NULL, new C_Inode_StoredParent(this, fin) ); + NULL, new C_Inode_StoredParent(this, inode.last_renamed_version, fin) ); } -void CInode::_stored_parent(Context *fin) +void CInode::_stored_parent(version_t v, Context *fin) { - dout(10) << "stored_parent" << dendl; + if (v == inode.last_renamed_version) { + dout(10) << "stored_parent committed v" << v << ", removing from list" << dendl; + xlist_renamed_file.remove_myself(); + state_clear(STATE_DIRTYPARENT); + } else { + dout(10) << "stored_parent committed v" << v << " < " << inode.last_renamed_version + << ", renamed again, not removing from list" << dendl; + } if (fin) { fin->finish(0); delete fin; diff --git a/src/mds/CInode.h b/src/mds/CInode.h index 0963a4b764022..695c7802d033e 100644 --- a/src/mds/CInode.h +++ b/src/mds/CInode.h @@ -124,6 +124,7 @@ public: static const int STATE_NEEDSRECOVER = (1<<11); static const int STATE_RECOVERING = (1<<12); static const int STATE_PURGING = (1<<13); + static const int STATE_DIRTYPARENT = (1<<14); // -- waiters -- static const __u64 WAIT_DIR = (1<<0); @@ -272,6 +273,7 @@ protected: public: xlist::item xlist_caps; xlist::item xlist_open_file; + xlist::item xlist_renamed_file; xlist::item xlist_dirty_dirfrag_dir; xlist::item xlist_dirty_dirfrag_nest; xlist::item xlist_dirty_dirfrag_dirfragtree; @@ -312,7 +314,7 @@ private: parent(0), inode_auth(CDIR_AUTH_DEFAULT), replica_caps_wanted(0), - xlist_dirty(this), xlist_caps(this), xlist_open_file(this), + xlist_dirty(this), xlist_caps(this), xlist_open_file(this), xlist_renamed_file(this), xlist_dirty_dirfrag_dir(this), xlist_dirty_dirfrag_nest(this), xlist_dirty_dirfrag_dirfragtree(this), @@ -401,7 +403,7 @@ private: void _fetched(bufferlist& bl, Context *fin); void store_parent(Context *fin); - void _stored_parent(Context *fin); + void _stored_parent(version_t v, Context *fin); void encode_parent_mutation(ObjectOperation& m); diff --git a/src/mds/LogSegment.h b/src/mds/LogSegment.h index 0b765f8cd3b7b..0bfdbfe372a04 100644 --- a/src/mds/LogSegment.h +++ b/src/mds/LogSegment.h @@ -41,6 +41,7 @@ class LogSegment { xlist dirty_dentries; xlist open_files; + xlist renamed_files; xlist dirty_dirfrag_dir; xlist dirty_dirfrag_nest; xlist dirty_dirfrag_dirfragtree; diff --git a/src/mds/Server.cc b/src/mds/Server.cc index 2f093689b2aa8..77becf9776105 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -4246,6 +4246,7 @@ void Server::_rename_prepare(MDRequest *mdr, if (!silent) { if (pi) { + pi->last_renamed_version = pi->version; pi->ctime = mdr->now; if (linkmerge) pi->nlink--; @@ -4456,7 +4457,15 @@ void Server::_rename_apply(MDRequest *mdr, CDentry *srcdn, CDentry *destdn, CDen } if (destdn->is_auth()) { - destdnl->get_inode()->pop_and_dirty_projected_inode(mdr->ls); + CInode *desti = destdnl->get_inode(); + desti->pop_and_dirty_projected_inode(mdr->ls); + + + if (desti->is_dir()) { + mdr->ls->renamed_files.push_back(&desti->xlist_renamed_file); + desti->state_set(CInode::STATE_DIRTYPARENT); + dout(10) << "added dir to logsegment renamed_files list " << *desti << dendl; + } } // snap parent update? diff --git a/src/mds/journal.cc b/src/mds/journal.cc index e26f2d6f7db46..0df174473aa61 100644 --- a/src/mds/journal.cc +++ b/src/mds/journal.cc @@ -174,6 +174,15 @@ C_Gather *LogSegment::try_to_expire(MDS *mds) } } + // parent pointers on renamed dirs + for (xlist::iterator p = renamed_files.begin(); !p.end(); ++p) { + CInode *in = *p; + dout(10) << "try_to_expire waiting for dir parent pointer update on " << *in << dendl; + assert(in->state_test(CInode::STATE_DIRTYPARENT)); + if (!gather) gather = new C_Gather; + in->store_parent(gather->new_sub()); + } + // slave updates for (xlist::iterator p = slave_updates.begin(); !p.end(); ++p) { MDSlaveUpdate *su = *p; diff --git a/src/mds/mdstypes.h b/src/mds/mdstypes.h index 42bdd122b790b..f585f5d6b9920 100644 --- a/src/mds/mdstypes.h +++ b/src/mds/mdstypes.h @@ -356,12 +356,14 @@ struct inode_t { version_t file_data_version; // auth only version_t xattr_version; + version_t last_renamed_version; // when i was last renamed + inode_t() : ino(0), rdev(0), mode(0), uid(0), gid(0), nlink(0), anchored(false), size(0), truncate_seq(0), truncate_size(0), truncate_from(0), time_warp_seq(0), - version(0), file_data_version(0), xattr_version(0) { + version(0), file_data_version(0), xattr_version(0), last_renamed_version(0) { memset(&layout, 0, sizeof(layout)); } @@ -397,7 +399,7 @@ struct inode_t { } void encode(bufferlist &bl) const { - __u8 v = 1; + __u8 v = 2; ::encode(v, bl); ::encode(ino, bl); @@ -428,6 +430,7 @@ struct inode_t { ::encode(version, bl); ::encode(file_data_version, bl); ::encode(xattr_version, bl); + ::encode(last_renamed_version, bl); } void decode(bufferlist::iterator &p) { __u8 v; @@ -461,6 +464,8 @@ struct inode_t { ::decode(version, p); ::decode(file_data_version, p); ::decode(xattr_version, p); + if (v >= 2) + ::decode(last_renamed_version, p); } }; WRITE_CLASS_ENCODER(inode_t) -- 2.39.5