]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: lookup snapped inodes by vinodeno_t 18942/head
authorYan, Zheng <zyan@redhat.com>
Wed, 15 Nov 2017 09:01:28 +0000 (17:01 +0800)
committerYan, Zheng <zyan@redhat.com>
Wed, 15 Nov 2017 09:41:28 +0000 (17:41 +0800)
Directory inodes are always multiversion, snapped metadata are stored
together with head inode. lookup snapped directory inodes is basically
the same as lookup head inodes.

For non-directory inode, there can be multiple version of snapped inodes,
and they can be stored in different dirfrags. To lookup a snapped inode,
client need to tell mds from which dirfrag it got the snapped inode.

Fixes: http://tracker.ceph.com/issues/22105
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
src/include/ceph_fs.h
src/mds/CInode.cc
src/mds/CInode.h
src/mds/MDCache.h
src/mds/Server.cc
src/mds/Server.h

index 4ddfda5be7b74eab727eadc513a8ca23f8bffa2d..9542a887ea3b9e8130be05a56e98194f2c5259b4 100644 (file)
@@ -549,6 +549,12 @@ union ceph_mds_request_args {
                __le64 length; /* num bytes to lock from start */
                __u8 wait; /* will caller wait for lock to become available? */
        } __attribute__ ((packed)) filelock_change;
+       struct {
+               __le32 mask;                 /* CEPH_CAP_* */
+               __le64 snapid;
+               __le64 parent;
+               __le32 hash;
+       } __attribute__ ((packed)) lookupino;
 } __attribute__ ((packed));
 
 #define CEPH_MDS_REQUEST_HEAD_VERSION  1
index 581ae2d0d91505eb098ffc33ec0be194553f6452..9512ebfbb1a586f5675fa4d7441129f4050bd7b6 100644 (file)
@@ -2593,6 +2593,24 @@ void CInode::pre_cow_old_inode()
     cow_old_inode(follows, true);
 }
 
+bool CInode::has_snap_data(snapid_t snapid)
+{
+  bool found = snapid >= first && snapid <= last;
+  if (!found && is_multiversion()) {
+    auto p = old_inodes.lower_bound(snapid);
+    if (p != old_inodes.end()) {
+      if (p->second.first > snapid) {
+       if  (p != old_inodes.begin())
+         --p;
+      }
+      if (p->second.first <= snapid && snapid <= p->first) {
+       found = true;
+      }
+    }
+  }
+  return found;
+}
+
 void CInode::purge_stale_snap_data(const set<snapid_t>& snaps)
 {
   dout(10) << "purge_stale_snap_data " << snaps << dendl;
index 01c942c9cf533e6fa48f59d8cc94af966026948d..f95f299f4a1cab85bf523357b0baf685a1c2bc03 100644 (file)
@@ -515,6 +515,7 @@ public:
   void split_old_inode(snapid_t snap);
   old_inode_t *pick_old_inode(snapid_t last);
   void pre_cow_old_inode();
+  bool has_snap_data(snapid_t s);
   void purge_stale_snap_data(const std::set<snapid_t>& snaps);
 
   // -- cache infrastructure --
index 8fd8472e378e8798de4d8d26c4a747ce15d7dd9b..2efaed3b6d3d75ec8c1707efead6488bdae8e207 100644 (file)
@@ -788,6 +788,13 @@ public:
   CInode* get_inode(inodeno_t ino, snapid_t s=CEPH_NOSNAP) {
     return get_inode(vinodeno_t(ino, s));
   }
+  CInode* lookup_snap_inode(vinodeno_t vino) {
+    auto p = snap_inode_map.lower_bound(vino);
+    if (p != snap_inode_map.end() &&
+       p->second->ino() == vino.ino && p->second->first <= vino.snapid)
+      return p->second;
+    return NULL;
+  }
 
   CDir* get_dirfrag(dirfrag_t df) {
     CInode *in = get_inode(df.ino);
index cdbee50c44f1a465700b73484580e65370bf628b..e72d8a7504e351a5852de0d79452950d9bacfb29 100644 (file)
@@ -3057,6 +3057,9 @@ void Server::handle_client_lookup_ino(MDRequestRef& mdr,
 {
   MClientRequest *req = mdr->client_request;
 
+  if ((uint64_t)req->head.args.lookupino.snapid > 0)
+    return _lookup_snap_ino(mdr);
+
   inodeno_t ino = req->get_filepath().get_ino();
   CInode *in = mdcache->get_inode(ino);
   if (in && in->state_test(CInode::STATE_PURGING)) {
@@ -3087,7 +3090,7 @@ void Server::handle_client_lookup_ino(MDRequestRef& mdr,
     rdlocks.insert(&dn->lock);
   }
 
-  unsigned mask = req->head.args.getattr.mask;
+  unsigned mask = req->head.args.lookupino.mask;
   if (mask) {
     Capability *cap = in->get_client_cap(mdr->get_client());
     int issued = 0;
@@ -3144,6 +3147,81 @@ void Server::handle_client_lookup_ino(MDRequestRef& mdr,
   }
 }
 
+void Server::_lookup_snap_ino(MDRequestRef& mdr)
+{
+  MClientRequest *req = mdr->client_request;
+
+  vinodeno_t vino;
+  vino.ino = req->get_filepath().get_ino();
+  vino.snapid = (__u64)req->head.args.lookupino.snapid;
+  inodeno_t parent_ino = (__u64)req->head.args.lookupino.parent;
+  __u32 hash = req->head.args.lookupino.hash;
+
+  dout(7) << "lookup_snap_ino " << vino << " parent " << parent_ino << " hash " << hash << dendl;
+
+  CInode *in = mdcache->lookup_snap_inode(vino);
+  if (!in) {
+    in = mdcache->get_inode(vino.ino);
+    if (in) {
+      if (in->state_test(CInode::STATE_PURGING) ||
+         !in->has_snap_data(vino.snapid)) {
+       if (in->is_dir() || !parent_ino) {
+         respond_to_request(mdr, -ESTALE);
+         return;
+       }
+       in = NULL;
+      }
+    }
+  }
+
+  if (in) {
+    dout(10) << "reply to lookup_snap_ino " << *in << dendl;
+    mdr->snapid = vino.snapid;
+    mdr->tracei = in;
+    respond_to_request(mdr, 0);
+    return;
+  }
+
+  CInode *diri = NULL;
+  if (parent_ino) {
+    diri = mdcache->get_inode(parent_ino);
+    if (!diri) {
+      mdcache->open_ino(parent_ino, mds->mdsmap->get_metadata_pool(), new C_MDS_LookupIno2(this, mdr));
+      return;
+    }
+
+    if (!diri->is_dir()) {
+      respond_to_request(mdr, -EINVAL);
+      return;
+    }
+
+    set<SimpleLock*> rdlocks, wrlocks, xlocks;
+    rdlocks.insert(&diri->dirfragtreelock);
+    if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks))
+      return;
+
+    frag_t frag = diri->dirfragtree[hash];
+    CDir *dir = try_open_auth_dirfrag(diri, frag, mdr);
+    if (!dir)
+      return;
+
+    if (!dir->is_complete()) {
+      if (dir->is_frozen()) {
+       mds->locker->drop_locks(mdr.get());
+       mdr->drop_local_auth_pins();
+       dir->add_waiter(CDir::WAIT_UNFREEZE, new C_MDS_RetryRequest(mdcache, mdr));
+       return;
+      }
+      dir->fetch(new C_MDS_RetryRequest(mdcache, mdr), true);
+      return;
+    }
+
+    respond_to_request(mdr, -ESTALE);
+  } else {
+    mdcache->open_ino(vino.ino, mds->mdsmap->get_metadata_pool(), new C_MDS_LookupIno2(this, mdr), false);
+  }
+}
+
 void Server::_lookup_ino_2(MDRequestRef& mdr, int r)
 {
   inodeno_t ino = mdr->client_request->get_filepath().get_ino();
index 2543953bab5fec2436641b2e0efbd78508c638dd..c0378a202c00b2effcaab5ce79610f81686de0e7 100644 (file)
@@ -192,6 +192,7 @@ public:
   void handle_client_getattr(MDRequestRef& mdr, bool is_lookup);
   void handle_client_lookup_ino(MDRequestRef& mdr,
                                bool want_parent, bool want_dentry);
+  void _lookup_snap_ino(MDRequestRef& mdr);
   void _lookup_ino_2(MDRequestRef& mdr, int r);
   void handle_client_readdir(MDRequestRef& mdr);
   void handle_client_file_setlock(MDRequestRef& mdr);