From 4852de618d9891973bd7b98b81a93c7f2e6f7231 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 6 Feb 2018 19:14:08 +0800 Subject: [PATCH] client: re-use free snap tag Fixes: https://tracker.ceph.com/issues/22829 Signed-off-by: "Yan, Zheng" --- src/client/Client.cc | 18 ++++++++++++++++++ src/client/Client.h | 4 ++++ src/client/fuse_ll.cc | 39 +++++++++++++++++++++++++++++++-------- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index 4265fa79b60..0cc8bb7b07d 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -10342,6 +10342,8 @@ void Client::_ll_get(Inode *in) assert(in->dentries.size() == 1); // dirs can't be hard-linked in->get_first_parent()->get(); // pin dentry } + if (in->snapid != CEPH_NOSNAP) + ll_snap_ref[in->snapid]++; } in->ll_get(); ldout(cct, 20) << __func__ << " " << in << " " << in->ino << " -> " << in->ll_ref << dendl; @@ -10356,6 +10358,13 @@ int Client::_ll_put(Inode *in, int num) assert(in->dentries.size() == 1); // dirs can't be hard-linked in->get_first_parent()->put(); // unpin dentry } + if (in->snapid != CEPH_NOSNAP) { + auto p = ll_snap_ref.find(in->snapid); + assert(p != ll_snap_ref.end()); + assert(p->second > 0); + if (--p->second == 0) + ll_snap_ref.erase(p); + } put_inode(in); return 0; } else { @@ -10414,6 +10423,15 @@ bool Client::ll_put(Inode *in) return ll_forget(in, 1); } +int Client::ll_get_snap_ref(snapid_t snap) +{ + Mutex::Locker lock(client_lock); + auto p = ll_snap_ref.find(snap); + if (p != ll_snap_ref.end()) + return p->second; + return 0; +} + snapid_t Client::ll_get_snapid(Inode *in) { Mutex::Locker lock(client_lock); diff --git a/src/client/Client.h b/src/client/Client.h index 2f1f66a1184..cd0506ee4c4 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -423,6 +423,8 @@ protected: void _reset_faked_inos(); vinodeno_t _map_faked_ino(ino_t ino); + std::map ll_snap_ref; + Inode* root; map root_parents; Inode* root_ancestor; @@ -1146,6 +1148,8 @@ public: const UserPerm& perms); bool ll_forget(Inode *in, int count); bool ll_put(Inode *in); + int ll_get_snap_ref(snapid_t snap); + int ll_getattr(Inode *in, struct stat *st, const UserPerm& perms); int ll_getattrx(Inode *in, struct ceph_statx *stx, unsigned int want, unsigned int flags, const UserPerm& perms); diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index 127e0ea9cee..947c8a4bca9 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -43,7 +43,8 @@ #define FINO_INO(x) ((x) & ((1ull<<48)-1ull)) #define FINO_STAG(x) ((x) >> 48) -#define MAKE_FINO(i,s) ((i) | ((s) << 48)) +#define MAKE_FINO(i,s) ((i) | ((int64_t)(s) << 48)) +#define STAG_MASK 0xffff #define MINORBITS 20 #define MINORMASK ((1U << MINORBITS) - 1) @@ -1225,13 +1226,35 @@ uint64_t CephFuse::Handle::make_fake_ino(inodeno_t ino, snapid_t snapid) return FUSE_ROOT_ID; Mutex::Locker l(stag_lock); - uint64_t stag; - if (snap_stag_map.count(snapid) == 0) { - stag = ++last_stag; - snap_stag_map[snapid] = stag; - stag_snap_map[stag] = snapid; - } else - stag = snap_stag_map[snapid]; + auto p = snap_stag_map.find(snapid); + if (p != snap_stag_map.end()) { + inodeno_t fino = MAKE_FINO(ino, p->second); + return fino; + } + + int first = last_stag & STAG_MASK; + int stag = (++last_stag) & STAG_MASK; + for (; stag != first; stag = (++last_stag) & STAG_MASK) { + if (stag == 0) + continue; + + auto p = stag_snap_map.find(stag); + if (p == stag_snap_map.end()) { + snap_stag_map[snapid] = stag; + stag_snap_map[stag] = snapid; + break; + } + + if (!client->ll_get_snap_ref(p->second)) { + snap_stag_map.erase(p->second); + snap_stag_map[snapid] = stag; + p->second = snapid; + break; + } + } + if (stag == first) + assert(0 == "run out of stag"); + inodeno_t fino = MAKE_FINO(ino, stag); //cout << "make_fake_ino " << ino << "." << snapid << " -> " << fino << std::endl; return fino; -- 2.39.5