From: Yan, Zheng Date: Wed, 15 Nov 2017 09:01:28 +0000 (+0800) Subject: mds: lookup snapped inodes by vinodeno_t X-Git-Tag: v13.0.1~113^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=01d2c37aad579e70e41b0e96e2e06e30bd9c0ce3;p=ceph.git mds: lookup snapped inodes by vinodeno_t 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" --- diff --git a/src/include/ceph_fs.h b/src/include/ceph_fs.h index 4ddfda5be7b..9542a887ea3 100644 --- a/src/include/ceph_fs.h +++ b/src/include/ceph_fs.h @@ -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 diff --git a/src/mds/CInode.cc b/src/mds/CInode.cc index 581ae2d0d91..9512ebfbb1a 100644 --- a/src/mds/CInode.cc +++ b/src/mds/CInode.cc @@ -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& snaps) { dout(10) << "purge_stale_snap_data " << snaps << dendl; diff --git a/src/mds/CInode.h b/src/mds/CInode.h index 01c942c9cf5..f95f299f4a1 100644 --- a/src/mds/CInode.h +++ b/src/mds/CInode.h @@ -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& snaps); // -- cache infrastructure -- diff --git a/src/mds/MDCache.h b/src/mds/MDCache.h index 8fd8472e378..2efaed3b6d3 100644 --- a/src/mds/MDCache.h +++ b/src/mds/MDCache.h @@ -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); diff --git a/src/mds/Server.cc b/src/mds/Server.cc index cdbee50c44f..e72d8a7504e 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -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 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(); diff --git a/src/mds/Server.h b/src/mds/Server.h index 2543953bab5..c0378a202c0 100644 --- a/src/mds/Server.h +++ b/src/mds/Server.h @@ -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);