From: Xiubo Li Date: Mon, 1 Mar 2021 02:05:05 +0000 (+0800) Subject: client: make Inode to inherit from RefCountedObject X-Git-Tag: v16.2.5~32^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=a03827a8276687db335f4535470df9c043c81f74;p=ceph.git client: make Inode to inherit from RefCountedObject This is also mainly one preparation for the inode lock feature, the InodeRef is useful in the case during the client_lock's unlock/lock gap, to make sure the Inode is not released. Fixes: https://tracker.ceph.com/issues/49536 Signed-off-by: Xiubo Li --- diff --git a/src/client/Client.cc b/src/client/Client.cc index a94876881abd..8132a0d15875 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -391,13 +391,7 @@ void Client::tear_down_cache() // close root ino ceph_assert(inode_map.size() <= 1 + root_parents.size()); if (root && inode_map.size() == 1 + root_parents.size()) { - delete root; - root = 0; - root_ancestor = 0; - while (!root_parents.empty()) - root_parents.erase(root_parents.begin()); - inode_map.clear(); - _reset_faked_inos(); + root.reset(); } ceph_assert(inode_map.empty()); @@ -416,7 +410,7 @@ Inode *Client::get_root() { std::scoped_lock l(client_lock); root->ll_get(); - return root; + return root.get(); } @@ -430,7 +424,7 @@ void Client::dump_inode(Formatter *f, Inode *in, set& did, bool disconne << (disconnected ? "DISCONNECTED ":"") << "inode " << in->ino << " " << path - << " ref " << in->get_num_ref() + << " ref " << in->get_nref() << " " << *in << dendl; if (f) { @@ -470,7 +464,7 @@ void Client::dump_cache(Formatter *f) f->open_array_section("cache"); if (root) - dump_inode(f, root, did, true); + dump_inode(f, root.get(), did, true); // make a second pass to catch anything disconnected for (ceph::unordered_map::iterator it = inode_map.begin(); @@ -705,15 +699,9 @@ void Client::trim_cache(bool trim_kernel_dcache) _invalidate_kernel_dcache(); // hose root? - if (lru.lru_get_size() == 0 && root && root->get_num_ref() == 0 && inode_map.size() == 1 + root_parents.size()) { + if (lru.lru_get_size() == 0 && root && root->get_nref() == 1 && inode_map.size() == 1 + root_parents.size()) { ldout(cct, 15) << "trim_cache trimmed root " << root << dendl; - delete root; - root = 0; - root_ancestor = 0; - while (!root_parents.empty()) - root_parents.erase(root_parents.begin()); - inode_map.clear(); - _reset_faked_inos(); + root.reset(); } } @@ -892,7 +880,7 @@ Inode * Client::add_update_inode(InodeStat *st, utime_t from, if (!root) { root = in; if (use_faked_inos()) - _assign_faked_root(root); + _assign_faked_root(root.get()); root_ancestor = in; cwd = root; } else if (is_mounting()) { @@ -3168,8 +3156,11 @@ void Client::_put_inode(Inode *in, int n) { ldout(cct, 10) << __func__ << " on " << *in << " n = " << n << dendl; - int left = in->_put(n); - if (left == 0) { + int left = in->get_nref(); + ceph_assert(left >= n + 1); + in->iput(n); + left -= n; + if (left == 1) { // the last one will be held by the inode_map // release any caps remove_all_caps(in); @@ -3180,14 +3171,13 @@ void Client::_put_inode(Inode *in, int n) if (use_faked_inos()) _release_faked_ino(in); - if (in == root) { - root = 0; + if (root == nullptr) { root_ancestor = 0; while (!root_parents.empty()) root_parents.erase(root_parents.begin()); } - delete in; + in->iput(); } } @@ -3338,12 +3328,12 @@ void Client::get_cap_ref(Inode *in, int cap) if ((cap & CEPH_CAP_FILE_BUFFER) && in->cap_refs[CEPH_CAP_FILE_BUFFER] == 0) { ldout(cct, 5) << __func__ << " got first FILE_BUFFER ref on " << *in << dendl; - in->get(); + in->iget(); } if ((cap & CEPH_CAP_FILE_CACHE) && in->cap_refs[CEPH_CAP_FILE_CACHE] == 0) { ldout(cct, 5) << __func__ << " got first FILE_CACHE ref on " << *in << dendl; - in->get(); + in->iget(); } in->get_cap_ref(cap); } @@ -5386,7 +5376,7 @@ void Client::_schedule_invalidate_dentry_callback(Dentry *dn, bool del) void Client::_try_to_trim_inode(Inode *in, bool sched_inval) { - int ref = in->get_num_ref(); + int ref = in->get_nref(); ldout(cct, 5) << __func__ << " in " << *in <dir && !in->dir->dentries.empty()) { @@ -5410,13 +5400,13 @@ void Client::_try_to_trim_inode(Inode *in, bool sched_inval) } } - if (ref > 0 && (in->flags & I_SNAPDIR_OPEN)) { + if (ref > 1 && (in->flags & I_SNAPDIR_OPEN)) { InodeRef snapdir = open_snapdir(in); _try_to_trim_inode(snapdir.get(), false); --ref; } - if (ref > 0) { + if (ref > 1) { auto q = in->dentries.begin(); while (q != in->dentries.end()) { Dentry *dn = *q; @@ -6224,7 +6214,7 @@ int Client::mount(const std::string &mount_root, const UserPerm& perms, } ceph_assert(root); - _ll_get(root); + _ll_get(root.get()); // trace? if (!cct->_conf->client_trace.empty()) { @@ -6385,6 +6375,7 @@ void Client::_unmount(bool abort) }); cwd.reset(); + root.reset(); // clean up any unclosed files while (!fd_map.empty()) { @@ -10551,7 +10542,7 @@ void Client::_getcwd(string& dir, const UserPerm& perms) ldout(cct, 10) << __func__ << " " << *cwd << dendl; Inode *in = cwd.get(); - while (in != root) { + while (in != root.get()) { ceph_assert(in->dentries.size() < 2); // dirs can't be hard-linked // A cwd or ancester is unlinked @@ -10654,7 +10645,7 @@ int Client::statfs(const char *path, struct statvfs *stbuf, // quota but we can see a parent of it that does have a quota, we'll // respect that one instead. ceph_assert(root != nullptr); - Inode *quota_root = root->quota.is_enable() ? root : get_quota_root(root, perms); + InodeRef quota_root = root->quota.is_enable() ? root : get_quota_root(root.get(), perms); // get_quota_root should always give us something // because client quotas are always enabled @@ -11527,7 +11518,7 @@ int Client::ll_walk(const char* name, Inode **out, struct ceph_statx *stx, void Client::_ll_get(Inode *in) { if (in->ll_ref == 0) { - in->get(); + in->iget(); if (in->is_dir() && !in->dentries.empty()) { ceph_assert(in->dentries.size() == 1); // dirs can't be hard-linked in->get_first_parent()->get(); // pin dentry @@ -15364,7 +15355,7 @@ void Client::handle_conf_change(const ConfigProxy& conf, void intrusive_ptr_add_ref(Inode *in) { - in->get(); + in->iget(); } void intrusive_ptr_release(Inode *in) diff --git a/src/client/Client.h b/src/client/Client.h index 011ff1ad07b9..629a3c863589 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -1056,7 +1056,7 @@ protected: std::map ll_snap_ref; - Inode* root = nullptr; + InodeRef root = nullptr; map root_parents; Inode* root_ancestor = nullptr; LRU lru; // lru list of Dentry's in our local metadata cache. diff --git a/src/client/Inode.cc b/src/client/Inode.cc index 69ca873d2765..5762759d00a4 100644 --- a/src/client/Inode.cc +++ b/src/client/Inode.cc @@ -40,7 +40,7 @@ ostream& operator<<(ostream &out, const Inode &in) { out << in.vino() << "(" << "faked_ino=" << in.faked_ino - << " ref=" << in._ref + << " nref=" << in.get_nref() << " ll_ref=" << in.ll_ref << " cap_refs=" << in.cap_refs << " open=" << in.open_by_mode @@ -379,7 +379,7 @@ Dir *Inode::open_dir() ceph_assert(dentries.size() < 2); // dirs can't be hard-linked if (!dentries.empty()) get_first_parent()->get(); // pin dentry - get(); // pin inode + iget(); // pin inode } return dir; } @@ -397,22 +397,6 @@ bool Inode::check_mode(const UserPerm& perms, unsigned want) return (mode & want) == want; } -void Inode::get() { - _ref++; - lsubdout(client->cct, client, 15) << "inode.get on " << this << " " << ino << '.' << snapid - << " now " << _ref << dendl; -} - -//private method to put a reference; see Client::put_inode() -int Inode::_put(int n) { - _ref -= n; - lsubdout(client->cct, client, 15) << "inode.put on " << this << " " << ino << '.' << snapid - << " now " << _ref << dendl; - ceph_assert(_ref >= 0); - return _ref; -} - - void Inode::dump(Formatter *f) const { f->dump_stream("ino") << ino; @@ -558,7 +542,7 @@ void Inode::dump(Formatter *f) const if (requested_max_size != max_size) f->dump_unsigned("requested_max_size", requested_max_size); - f->dump_int("ref", _ref); + f->dump_int("nref", get_nref()); f->dump_int("ll_ref", ll_ref); if (!dentries.empty()) { @@ -790,7 +774,7 @@ void Inode::mark_caps_dirty(int caps) lsubdout(client->cct, client, 10) << __func__ << " " << *this << " " << ccap_string(dirty_caps) << " -> " << ccap_string(dirty_caps | caps) << dendl; if (caps && !caps_dirty()) - get(); + iget(); dirty_caps |= caps; client->get_dirty_list().push_back(&dirty_cap_item); } diff --git a/src/client/Inode.h b/src/client/Inode.h index 22930eb8b9a3..4144cfa25c9d 100644 --- a/src/client/Inode.h +++ b/src/client/Inode.h @@ -114,7 +114,7 @@ struct CapSnap { #define I_CAP_DROPPED (1 << 4) #define I_ERROR_FILELOCK (1 << 5) -struct Inode { +struct Inode : RefCountedObject { Client *client; // -- the actual inode -- @@ -229,7 +229,6 @@ struct Inode { uint64_t wanted_max_size = 0; uint64_t requested_max_size = 0; - int _ref = 0; // ref count. 1 for each dentry, fh that links to me. uint64_t ll_ref = 0; // separate ref count for ll client xlist dentries; // if i'm linked to a dentry. string symlink; // symlink content, if it's a symlink @@ -250,12 +249,10 @@ struct Inode { void make_short_path(filepath& p); void make_nosnap_relative_path(filepath& p); - void get(); - int _put(int n=1); - - int get_num_ref() { - return _ref; - } + // The ref count. 1 for each dentry, fh, inode_map, + // cwd that links to me. + void iget() { get(); } + void iput(int n=1) { ceph_assert(n >= 0); while (n--) put(); } void ll_get() { ll_ref++;