CEPH_MDS_OP_FLUSH = 0x01502,
CEPH_MDS_OP_ENQUEUE_SCRUB = 0x01503,
CEPH_MDS_OP_REPAIR_FRAGSTATS = 0x01504,
- CEPH_MDS_OP_REPAIR_INODESTATS = 0x01505
+ CEPH_MDS_OP_REPAIR_INODESTATS = 0x01505,
+ CEPH_MDS_OP_UPGRADE_SNAPREALM = 0x01506
};
extern const char *ceph_mds_op_name(int op);
new_srnode->seq = snaprealm->get_newest_seq();
new_srnode->past_parents.clear();
}
+ if (snaprealm)
+ snaprealm->past_parents_dirty = false;
} else {
if (snapid == 0)
snapid = mdcache->get_global_snaprealm()->get_newest_seq();
START = 0,
BACKTRACE,
INODE,
- DIRFRAGS
+ DIRFRAGS,
+ SNAPREALM,
};
ValidationContinuation(CInode *i,
set_callback(BACKTRACE, static_cast<Continuation::stagePtr>(&ValidationContinuation::_backtrace));
set_callback(INODE, static_cast<Continuation::stagePtr>(&ValidationContinuation::_inode_disk));
set_callback(DIRFRAGS, static_cast<Continuation::stagePtr>(&ValidationContinuation::_dirfrags));
+ set_callback(SNAPREALM, static_cast<Continuation::stagePtr>(&ValidationContinuation::_snaprealm));
}
~ValidationContinuation() override {
return true;
}
+ // prefetch snaprealm's past parents
+ if (in->snaprealm && !in->snaprealm->have_past_parents_open())
+ in->snaprealm->open_parents(nullptr);
+
C_OnFinisher *conf = new C_OnFinisher(get_io_callback(BACKTRACE),
in->mdcache->mds->finisher);
}
}
- // quit if we're a file, or kick off directory checks otherwise
- // TODO: validate on-disk inode for non-base directories
- if (!in->is_dir()) {
- return true;
- }
- return validate_directory_data();
+ if (in->is_dir()) {
+ return validate_directory_data();
+ } else {
+ // TODO: validate on-disk inode for normal files
+ return check_inode_snaprealm();
+ }
}
bool validate_directory_data() {
shadow_in->fetch(get_internal_callback(INODE));
return false;
} else {
+ // TODO: validate on-disk inode for non-base directories
results->inode.passed = true;
- return check_dirfrag_rstats();
+ return check_dirfrag_rstats();
}
}
mempool_inode& i = in->inode;
if (si.version > i.version) {
// uh, what?
- results->inode.error_str << "On-disk inode is newer than in-memory one!";
+ results->inode.error_str << "On-disk inode is newer than in-memory one; ";
goto next;
} else {
bool divergent = false;
results->inode.passed = !divergent && r >= 0;
if (!results->inode.passed) {
results->inode.error_str <<
- "On-disk inode is divergent or newer than in-memory one!";
+ "On-disk inode is divergent or newer than in-memory one; ";
goto next;
}
}
results->raw_stats.passed = true;
next:
+ // snaprealm
+ return check_inode_snaprealm();
+ }
+
+ bool check_inode_snaprealm() {
+ if (!in->snaprealm)
+ return true;
+
+ if (!in->snaprealm->have_past_parents_open()) {
+ in->snaprealm->open_parents(get_internal_callback(SNAPREALM));
+ return false;
+ } else {
+ return immediate(SNAPREALM, 0);
+ }
+ }
+
+ bool _snaprealm(int rval) {
+
+ if (in->snaprealm->past_parents_dirty ||
+ !in->get_projected_srnode()->past_parents.empty()) {
+ // temporarily store error in field of on-disk inode validation temporarily
+ results->inode.checked = true;
+ results->inode.passed = false;
+ if (in->scrub_infop->header->get_repair()) {
+ results->inode.error_str << "Inode has old format snaprealm (will upgrade)";
+ results->inode.repaired = true;
+ in->mdcache->upgrade_inode_snaprealm(in);
+ } else {
+ results->inode.error_str << "Inode has old format snaprealm";
+ }
+ }
return true;
}
case CEPH_MDS_OP_REPAIR_INODESTATS:
repair_inode_stats_work(mdr);
break;
+ case CEPH_MDS_OP_UPGRADE_SNAPREALM:
+ upgrade_inode_snaprealm_work(mdr);
+ break;
default:
ceph_abort();
}
return;
}
-struct C_MDC_RepairDirfragStats : public MDCacheLogContext {
+struct C_MDC_RespondInternalRequest : public MDCacheLogContext {
MDRequestRef mdr;
- C_MDC_RepairDirfragStats(MDCache *c, MDRequestRef& m) :
+ C_MDC_RespondInternalRequest(MDCache *c, MDRequestRef& m) :
MDCacheLogContext(c), mdr(m) {}
void finish(int r) override {
mdr->apply();
le->metablob.add_dir_context(dir);
le->metablob.add_dir(dir, true);
- mds->mdlog->submit_entry(le, new C_MDC_RepairDirfragStats(this, mdr));
+ mds->mdlog->submit_entry(le, new C_MDC_RespondInternalRequest(this, mdr));
}
void MDCache::repair_inode_stats(CInode *diri)
mds->server->respond_to_request(mdr, 0);
}
+void MDCache::upgrade_inode_snaprealm(CInode *in)
+{
+ MDRequestRef mdr = request_start_internal(CEPH_MDS_OP_UPGRADE_SNAPREALM);
+ mdr->pin(in);
+ mdr->internal_op_private = in;
+ mdr->internal_op_finish = new C_MDSInternalNoop;
+ upgrade_inode_snaprealm_work(mdr);
+}
+
+void MDCache::upgrade_inode_snaprealm_work(MDRequestRef& mdr)
+{
+ CInode *in = static_cast<CInode*>(mdr->internal_op_private);
+ dout(10) << __func__ << " " << *in << dendl;
+
+ if (!in->is_auth()) {
+ mds->server->respond_to_request(mdr, -ESTALE);
+ return;
+ }
+
+ set<SimpleLock*> rdlocks, wrlocks, xlocks;
+ mds->locker->include_snap_rdlocks(rdlocks, in);
+ rdlocks.erase(&in->snaplock);
+ xlocks.insert(&in->snaplock);
+
+ if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks))
+ return;
+
+ // project_snaprealm() upgrades snaprealm format
+ auto &pi = in->project_inode(false, true);
+ mdr->add_projected_inode(in);
+ pi.inode.version = in->pre_dirty();
+
+ mdr->ls = mds->mdlog->get_current_segment();
+ EUpdate *le = new EUpdate(mds->mdlog, "upgrade_snaprealm");
+ mds->mdlog->start_entry(le);
+
+ if (in->is_base()) {
+ le->metablob.add_root(true, in, in->get_projected_inode());
+ } else {
+ CDentry *pdn = in->get_projected_parent_dn();
+ le->metablob.add_dir_context(pdn->get_dir());
+ le->metablob.add_primary_dentry(pdn, in, true);
+ }
+
+ mds->mdlog->submit_entry(le, new C_MDC_RespondInternalRequest(this, mdr));
+}
+
void MDCache::flush_dentry(std::string_view path, Context *fin)
{
if (is_readonly()) {
void enqueue_scrub_work(MDRequestRef& mdr);
void repair_inode_stats_work(MDRequestRef& mdr);
void repair_dirfrag_stats_work(MDRequestRef& mdr);
- friend class C_MDC_RepairDirfragStats;
+ void upgrade_inode_snaprealm_work(MDRequestRef& mdr);
+ friend class C_MDC_RespondInternalRequest;
public:
void flush_dentry(std::string_view path, Context *fin);
/**
Formatter *f, Context *fin);
void repair_inode_stats(CInode *diri);
void repair_dirfrag_stats(CDir *dir);
+ void upgrade_inode_snaprealm(CInode *in);
public:
/* Because exports may fail, this set lets us keep track of inodes that need exporting. */
}
SnapRealm::SnapRealm(MDCache *c, CInode *in) :
- mdcache(c), inode(in), open(false), parent(0),
+ mdcache(c), inode(in), parent(nullptr),
num_open_past_parents(0), inodes_with_caps(0)
{
global = (inode->ino() == MDS_INO_GLOBAL_SNAPREALM);
void finish(int r) override {
if (r < 0)
sr->_remove_missing_parent(parent_last, parent, r);
- if (sr->_open_parents(fin, first, last))
- fin->complete(0);
+ if (sr->_open_parents(fin, first, last)) {
+ if (fin)
+ fin->complete(0);
+ }
sr->inode->put(CInode::PIN_OPENINGSNAPPARENTS);
}
};
dout(10) << __func__ << " " << parent << " [" << p->second.first << ","
<< p->first << "] errno " << err << dendl;
srnode.past_parents.erase(p);
+ past_parents_dirty = true;
} else {
dout(10) << __func__ << " " << parent << " not found" << dendl;
}
if (parent->state_test(CInode::STATE_PURGING)) {
dout(10) << " skip purging past_parent " << *parent << dendl;
srnode.past_parents.erase(p++);
+ past_parents_dirty = true;
continue;
}
assert(parent->snaprealm); // hmm!
srnode.past_parent_snaps.insert(*p);
}
srnode.past_parents.clear();
+ past_parents_dirty = true;
}
for (auto p = srnode.past_parent_snaps.begin();
MDCache *mdcache;
CInode *inode;
- mutable bool open; // set to true once all past_parents are opened
+ mutable bool open = false; // set to true once all past_parents are opened
+ bool past_parents_dirty = false;
bool global;
SnapRealm *parent;