// snap trace
SnapRealm *realm = NULL;
if (reply->snapbl.length())
- update_snap_trace(reply->snapbl, &realm);
+ update_snap_trace(session, reply->snapbl, &realm);
ldout(cct, 10) << " hrm "
<< " is_target=" << (int)reply->head.is_target
return !new_snapc.snaps.empty() && new_snapc.snaps[0] > old_snapc.seq;
}
+struct SnapRealmInfoMeta {
+ SnapRealmInfoMeta(utime_t last_modified, uint64_t change_attr)
+ : last_modified(last_modified),
+ change_attr(change_attr) {
+ }
+
+ utime_t last_modified;
+ uint64_t change_attr;
+};
+
+static std::pair<SnapRealmInfo, std::optional<SnapRealmInfoMeta>> get_snap_realm_info(
+ MetaSession *session, bufferlist::const_iterator &p) {
+ if (session->mds_features.test(CEPHFS_FEATURE_NEW_SNAPREALM_INFO)) {
+ SnapRealmInfoNew ninfo;
+ decode(ninfo, p);
+ return std::make_pair(ninfo.info, SnapRealmInfoMeta(ninfo.last_modified, ninfo.change_attr));
+ } else {
+ SnapRealmInfo info;
+ decode(info, p);
+ return std::make_pair(info, std::nullopt);
+ }
+}
+
-void Client::update_snap_trace(const bufferlist& bl, SnapRealm **realm_ret, bool flush)
+void Client::update_snap_trace(MetaSession *session, const bufferlist& bl, SnapRealm **realm_ret, bool flush)
{
SnapRealm *first_realm = NULL;
ldout(cct, 10) << __func__ << " len " << bl.length() << dendl;
auto p = bl.cbegin();
while (!p.end()) {
- SnapRealmInfo info;
- decode(info, p);
+ auto [info, realm_info_meta] = get_snap_realm_info(session, p);
SnapRealm *realm = get_snap_realm(info.ino());
bool invalidate = false;
- if (info.seq() > realm->seq) {
+ if (info.seq() > realm->seq ||
+ (realm_info_meta && (*realm_info_meta).change_attr > realm->change_attr)) {
ldout(cct, 10) << __func__ << " " << *realm << " seq " << info.seq() << " > " << realm->seq
- << dendl;
+ << dendl;
if (flush) {
// writeback any dirty caps _before_ updating snap list (i.e. with old snap info)
realm->created = info.created();
realm->parent_since = info.parent_since();
realm->prior_parent_snaps = info.prior_parent_snaps;
+ if (realm_info_meta) {
+ realm->last_modified = (*realm_info_meta).last_modified;
+ realm->change_attr = (*realm_info_meta).change_attr;
+ }
realm->my_snaps = info.my_snaps;
invalidate = true;
}
if (m->head.op == CEPH_SNAP_OP_SPLIT) {
ceph_assert(m->head.split);
- SnapRealmInfo info;
auto p = m->bl.cbegin();
- decode(info, p);
+ auto [info, _] = get_snap_realm_info(session.get(), p);
ceph_assert(info.ino() == m->head.split);
// flush, then move, ino's.
}
}
- update_snap_trace(m->bl, NULL, m->head.op != CEPH_SNAP_OP_DESTROY);
+ update_snap_trace(session.get(), m->bl, NULL, m->head.op != CEPH_SNAP_OP_DESTROY);
if (realm) {
for (auto p = to_move.begin(); p != to_move.end(); ++p) {
// add/update it
SnapRealm *realm = NULL;
- update_snap_trace(m->snapbl, &realm);
+ update_snap_trace(session, m->snapbl, &realm);
int issued = m->get_caps();
int wanted = m->get_wanted();
in->uid = diri->uid;
in->gid = diri->gid;
in->nlink = 1;
- in->mtime = diri->mtime;
- in->ctime = diri->ctime;
+ in->mtime = diri->snaprealm->last_modified;
+ in->ctime = in->mtime;
+ in->change_attr = diri->snaprealm->change_attr;
in->btime = diri->btime;
in->atime = diri->atime;
in->size = diri->size;
- in->change_attr = diri->change_attr;
in->dirfragtree.clear();
in->snapdir_parent = diri;
SnapRealm *pparent;
std::set<SnapRealm*> pchildren;
+ utime_t last_modified;
+ uint64_t change_attr;
private:
SnapContext cached_snap_context; // my_snaps + parent snaps + past_parent_snaps
explicit SnapRealm(inodeno_t i) :
ino(i), nref(0), created(0), seq(0),
- pparent(NULL) { }
+ pparent(NULL), last_modified(utime_t()), change_attr(0) { }
void build_snap_context();
void invalidate_cache() {
<< " parent=" << r.parent
<< " my_snaps=" << r.my_snaps
<< " cached_snapc=" << r.cached_snap_context
+ << " last_modified=" << r.last_modified
+ << " change_attr=" << r.change_attr
<< ")";
}