]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: journal snap inodes that need flush when expiring log segment
authorYan, Zheng <zyan@redhat.com>
Tue, 21 Jun 2016 09:17:56 +0000 (17:17 +0800)
committerYan, Zheng <zyan@redhat.com>
Wed, 20 Jul 2016 02:34:00 +0000 (10:34 +0800)
Treat snap inodes that need flush in the same way as open files.
When MDS recovers, this make sure that journal replay bring snap
inodes that need flush into the cache

Signed-off-by: Yan, Zheng <zyan@redhat.com>
(cherry picked from commit 306153b3d012832bdfa20402077fa60a9a5d626c)

src/mds/CInode.h
src/mds/Locker.cc
src/mds/MDCache.cc
src/mds/events/EMetaBlob.h
src/mds/events/EOpen.h
src/mds/journal.cc

index 5ed80a617547a12c6698f592f3d3f1566ba818d9..217257cca90fae6ecd32e4c1e461a2b66ea2cc2f 100644 (file)
@@ -560,8 +560,8 @@ protected:
   compact_map<int32_t, int32_t>      mds_caps_wanted;     // [auth] mds -> caps wanted
   int                   replica_caps_wanted; // [replica] what i've requested from auth
 
-  compact_map<int, std::set<client_t> > client_snap_caps;     // [auth] [snap] dirty metadata we still need from the head
 public:
+  compact_map<int, std::set<client_t> > client_snap_caps;     // [auth] [snap] dirty metadata we still need from the head
   compact_map<snapid_t, std::set<client_t> > client_need_snapflush;
 
   void add_need_snapflush(CInode *snapin, snapid_t snapid, client_t client);
index 84e0e4897944874a0d4da6004f8e1cae15eec681..bd010227d677299ab963931dac6642bad01c0fac 100644 (file)
@@ -1750,8 +1750,11 @@ void Locker::file_update_finish(CInode *in, MutationRef& mut, bool share, client
       } else
        ++p;
     }
-    if (gather)
+    if (gather) {
+      if (in->client_snap_caps.empty())
+       in->item_open_file.remove_myself();
       eval_cap_gather(in, &need_issue);
+    }
   } else {
     if (cap && (cap->wanted() & ~cap->pending()) &&
        need_issue.count(in) == 0) {  // if we won't issue below anyway
index a0f2fa02a6d40d71ea12cf435c36bd36c0a87480..101b3820db6e4db8063fea71a4c74c98d1d79631 100644 (file)
@@ -1698,7 +1698,10 @@ void MDCache::journal_cow_dentry(MutationImpl *mut, EMetaBlob *metablob,
       CDentry *olddn = dn->dir->add_primary_dentry(dn->name, oldin, oldfirst, follows);
       oldin->inode.version = olddn->pre_dirty();
       dout(10) << " olddn " << *olddn << dendl;
-      metablob->add_primary_dentry(olddn, 0, true);
+      bool need_snapflush = !oldin->client_snap_caps.empty();
+      if (need_snapflush)
+       mut->ls->open_files.push_back(&oldin->item_open_file);
+      metablob->add_primary_dentry(olddn, 0, true, false, false, need_snapflush);
       mut->add_cow_dentry(olddn);
     } else {
       assert(dnl->is_remote());
@@ -5497,14 +5500,21 @@ void MDCache::clean_open_file_lists()
        p != mds->mdlog->segments.end();
        ++p) {
     LogSegment *ls = p->second;
-    
+
     elist<CInode*>::iterator q = ls->open_files.begin(member_offset(CInode, item_open_file));
     while (!q.end()) {
       CInode *in = *q;
       ++q;
-      if (!in->is_any_caps_wanted()) {
-       dout(10) << " unlisting unwanted/capless inode " << *in << dendl;
-       in->item_open_file.remove_myself();
+      if (in->last == CEPH_NOSNAP) {
+       if (!in->is_any_caps_wanted()) {
+         dout(10) << " unlisting unwanted/capless inode " << *in << dendl;
+         in->item_open_file.remove_myself();
+       }
+      } else if (in->last != CEPH_NOSNAP) {
+       if (in->client_snap_caps.empty()) {
+         dout(10) << " unlisting flushed snap inode " << *in << dendl;
+         in->item_open_file.remove_myself();
+       }
       }
     }
   }
index 77f8c3c43be72e5845634f1c64f1886c1f280e93..777152e246a45ed6da6f600955bb37e3edc6b209 100644 (file)
@@ -62,6 +62,7 @@ public:
     static const int STATE_DIRTY =      (1<<0);
     static const int STATE_DIRTYPARENT = (1<<1);
     static const int STATE_DIRTYPOOL   = (1<<2);
+    static const int STATE_NEED_SNAPFLUSH = (1<<3);
     typedef compact_map<snapid_t, old_inode_t> old_inodes_t;
     string  dn;         // dentry
     snapid_t dnfirst, dnlast;
@@ -109,6 +110,7 @@ public:
     bool is_dirty() const { return (state & STATE_DIRTY); }
     bool is_dirty_parent() const { return (state & STATE_DIRTYPARENT); }
     bool is_dirty_pool() const { return (state & STATE_DIRTYPOOL); }
+    bool need_snapflush() const { return (state & STATE_NEED_SNAPFLUSH); }
 
     void print(ostream& out) const {
       out << " fullbit dn " << dn << " [" << dnfirst << "," << dnlast << "] dnv " << dnv
@@ -420,11 +422,13 @@ private:
 
   // return remote pointer to to-be-journaled inode
   void add_primary_dentry(CDentry *dn, CInode *in, bool dirty,
-                         bool dirty_parent=false, bool dirty_pool=false) {
+                         bool dirty_parent=false, bool dirty_pool=false,
+                         bool need_snapflush=false) {
     __u8 state = 0;
     if (dirty) state |= fullbit::STATE_DIRTY;
     if (dirty_parent) state |= fullbit::STATE_DIRTYPARENT;
     if (dirty_pool) state |= fullbit::STATE_DIRTYPOOL;
+    if (need_snapflush) state |= fullbit::STATE_NEED_SNAPFLUSH;
     add_primary_dentry(add_dir(dn->get_dir(), false), dn, in, state);
   }
   void add_primary_dentry(dirlump& lump, CDentry *dn, CInode *in, __u8 state) {
index c48d7350546e5cb81546b59c0cdfb9e5a6a87062..601652a5e951598bcf49abbc2157c29bb8d15144 100644 (file)
@@ -22,6 +22,7 @@ class EOpen : public LogEvent {
 public:
   EMetaBlob metablob;
   vector<inodeno_t> inos;
+  vector<vinodeno_t> snap_inos;
 
   EOpen() : LogEvent(EVENT_OPEN) { }
   explicit EOpen(MDLog *mdlog) :
@@ -37,7 +38,10 @@ public:
     if (!in->is_base()) {
       metablob.add_dir_context(in->get_projected_parent_dn()->get_dir());
       metablob.add_primary_dentry(in->get_projected_parent_dn(), 0, false);
-      inos.push_back(in->ino());
+      if (in->last == CEPH_NOSNAP)
+       inos.push_back(in->ino());
+      else
+       snap_inos.push_back(in->vino());
     }
   }
   void add_ino(inodeno_t ino) {
index 0f27971b1326f2259d77650161b1108f146fd0c5..fd7aaf8d5aeea5b698adce8b92eee37b2d68d1a6 100644 (file)
@@ -147,7 +147,7 @@ void LogSegment::try_to_expire(MDSRank *mds, MDSGatherBuilder &gather_bld, int o
 
   assert(g_conf->mds_kill_journal_expire_at != 2);
 
-  // open files
+  // open files and snap inodes 
   if (!open_files.empty()) {
     assert(!mds->mdlog->is_capped()); // hmm FIXME
     EOpen *le = 0;
@@ -156,9 +156,9 @@ void LogSegment::try_to_expire(MDSRank *mds, MDSGatherBuilder &gather_bld, int o
     elist<CInode*>::iterator p = open_files.begin(member_offset(CInode, item_open_file));
     while (!p.end()) {
       CInode *in = *p;
-      assert(in->last == CEPH_NOSNAP);
       ++p;
-      if (in->is_auth() && !in->is_ambiguous_auth() && in->is_any_caps()) {
+      if (in->last == CEPH_NOSNAP && in->is_auth() &&
+         !in->is_ambiguous_auth() && in->is_any_caps()) {
        if (in->is_any_caps_wanted()) {
          dout(20) << "try_to_expire requeueing open file " << *in << dendl;
          if (!le) {
@@ -172,6 +172,15 @@ void LogSegment::try_to_expire(MDSRank *mds, MDSGatherBuilder &gather_bld, int o
          dout(20) << "try_to_expire not requeueing and delisting unwanted file " << *in << dendl;
          in->item_open_file.remove_myself();
        }
+      } else if (in->last != CEPH_NOSNAP && !in->client_snap_caps.empty()) {
+       // journal snap inodes that need flush. This simplify the mds failover hanlding
+       dout(20) << "try_to_expire requeueing snap needflush inode " << *in << dendl;
+       if (!le) {
+         le = new EOpen(mds->mdlog);
+         mds->mdlog->start_entry(le);
+       }
+       le->add_clean_inode(in);
+       ls->open_files.push_back(&in->item_open_file);
       } else {
        /*
         * we can get a capless inode here if we replay an open file, the client fails to
@@ -1332,6 +1341,8 @@ void EMetaBlob::replay(MDSRank *mds, LogSegment *logseg, MDSlaveUpdate *slaveup)
        in->_mark_dirty(logseg);
       if (p->is_dirty_parent())
        in->_mark_dirty_parent(logseg, p->is_dirty_pool());
+      if (p->need_snapflush())
+       logseg->open_files.push_back(&in->item_open_file);
       if (dn->is_auth())
        in->state_set(CInode::STATE_AUTH);
       else
@@ -2120,10 +2131,11 @@ void EUpdate::replay(MDSRank *mds)
 // EOpen
 
 void EOpen::encode(bufferlist &bl, uint64_t features) const {
-  ENCODE_START(3, 3, bl);
+  ENCODE_START(4, 3, bl);
   ::encode(stamp, bl);
   ::encode(metablob, bl, features);
   ::encode(inos, bl);
+  ::encode(snap_inos, bl);
   ENCODE_FINISH(bl);
 } 
 
@@ -2133,6 +2145,8 @@ void EOpen::decode(bufferlist::iterator &bl) {
     ::decode(stamp, bl);
   ::decode(metablob, bl);
   ::decode(inos, bl);
+  if (struct_v >= 4)
+    ::decode(snap_inos, bl);
   DECODE_FINISH(bl);
 }
 
@@ -2167,12 +2181,18 @@ void EOpen::replay(MDSRank *mds)
   metablob.replay(mds, _segment);
 
   // note which segments inodes belong to, so we don't have to start rejournaling them
-  for (vector<inodeno_t>::iterator p = inos.begin();
-       p != inos.end();
-       ++p) {
-    CInode *in = mds->mdcache->get_inode(*p);
+  for (const auto &ino : inos) {
+    CInode *in = mds->mdcache->get_inode(ino);
+    if (!in) {
+      dout(0) << "EOpen.replay ino " << ino << " not in metablob" << dendl;
+      assert(in);
+    }
+    _segment->open_files.push_back(&in->item_open_file);
+  }
+  for (const auto &vino : snap_inos) {
+    CInode *in = mds->mdcache->get_inode(vino);
     if (!in) {
-      dout(0) << "EOpen.replay ino " << *p << " not in metablob" << dendl;
+      dout(0) << "EOpen.replay ino " << vino << " not in metablob" << dendl;
       assert(in);
     }
     _segment->open_files.push_back(&in->item_open_file);