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).
- 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?
- 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
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);
}
};
_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;
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) );
}
*
* @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);
void _commit_full(ObjectOperation& m, const set<snapid_t> *snaps);
void _commit_partial(ObjectOperation& m, const set<snapid_t> *snaps);
void _encode_dentry(CDentry *dn, bufferlist& bl, const set<snapid_t> *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 --
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";
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);
}
};
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;
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);
public:
xlist<CInode*>::item xlist_caps;
xlist<CInode*>::item xlist_open_file;
+ xlist<CInode*>::item xlist_renamed_file;
xlist<CInode*>::item xlist_dirty_dirfrag_dir;
xlist<CInode*>::item xlist_dirty_dirfrag_nest;
xlist<CInode*>::item xlist_dirty_dirfrag_dirfragtree;
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),
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);
xlist<CDentry*> dirty_dentries;
xlist<CInode*> open_files;
+ xlist<CInode*> renamed_files;
xlist<CInode*> dirty_dirfrag_dir;
xlist<CInode*> dirty_dirfrag_nest;
xlist<CInode*> dirty_dirfrag_dirfragtree;
if (!silent) {
if (pi) {
+ pi->last_renamed_version = pi->version;
pi->ctime = mdr->now;
if (linkmerge)
pi->nlink--;
}
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?
}
}
+ // parent pointers on renamed dirs
+ for (xlist<CInode*>::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<MDSlaveUpdate*>::iterator p = slave_updates.begin(); !p.end(); ++p) {
MDSlaveUpdate *su = *p;
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));
}
}
void encode(bufferlist &bl) const {
- __u8 v = 1;
+ __u8 v = 2;
::encode(v, bl);
::encode(ino, bl);
::encode(version, bl);
::encode(file_data_version, bl);
::encode(xattr_version, bl);
+ ::encode(last_renamed_version, bl);
}
void decode(bufferlist::iterator &p) {
__u8 v;
::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)