#include "mds/flock.h"
+using std::dec;
+using std::list;
+using std::oct;
+using std::ostream;
+using std::string;
+
Inode::~Inode()
{
delay_cap_item.remove_myself();
{
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
dn->dir->parent_inode->make_long_path(p);
p.push_dentry(dn->name);
} else if (snapdir_parent) {
- snapdir_parent->make_nosnap_relative_path(p);
- string empty;
- p.push_dentry(empty);
+ make_nosnap_relative_path(p);
+ } else
+ p = filepath(ino);
+}
+
+void Inode::make_short_path(filepath& p)
+{
+ if (!dentries.empty()) {
+ Dentry *dn = get_first_parent();
+ ceph_assert(dn->dir && dn->dir->parent_inode);
+ p = filepath(dn->name, dn->dir->parent_inode->ino);
+ } else if (snapdir_parent) {
+ make_nosnap_relative_path(p);
} else
p = filepath(ino);
}
void Inode::get_open_ref(int mode)
{
+ client->inc_opened_files();
+ if (open_by_mode[mode] == 0) {
+ client->inc_opened_inodes();
+ }
open_by_mode[mode]++;
break_deleg(!(mode & CEPH_FILE_MODE_WR));
}
//cout << "open_by_mode[" << mode << "] " << open_by_mode[mode] << " -> " << (open_by_mode[mode]-1) << std::endl;
auto& ref = open_by_mode.at(mode);
ceph_assert(ref > 0);
- if (--ref == 0)
+ client->dec_opened_files();
+ if (--ref == 0) {
+ client->dec_opened_inodes();
return true;
+ }
return false;
}
{
int c = snap_caps;
int i = 0;
- for (const auto &pair : caps) {
- const Cap &cap = pair.second;
+ for (const auto &[mds, cap] : caps) {
if (cap_is_valid(cap)) {
c |= cap.issued;
i |= cap.implemented;
* This is the bog standard "check whether we have the required caps" operation.
* Typically, we only check against the capset that is currently "issued".
* In other words, we ignore caps that have been revoked but not yet released.
+ * Also account capability hit/miss stats.
*
* Some callers (particularly those doing attribute retrieval) can also make
* use of the full set of "implemented" caps to satisfy requests from the
cap_is_valid(*auth_cap) &&
(auth_cap->issued & mask) == mask) {
auth_cap->touch();
+ client->cap_hit();
return true;
}
// try any cap
if (cap_is_valid(cap)) {
if ((cap.issued & mask) == mask) {
cap.touch();
+ client->cap_hit();
return true;
}
c |= cap.issued;
for (auto &pair : caps) {
pair.second.touch();
}
+ client->cap_hit();
return true;
}
+
+ client->cap_miss();
return false;
}
int Inode::caps_used()
{
int w = 0;
- for (map<int,int>::iterator p = cap_refs.begin();
- p != cap_refs.end();
- ++p)
- if (p->second)
- w |= p->first;
+ for (const auto &[cap, cnt] : cap_refs)
+ if (cnt)
+ w |= cap;
return w;
}
int Inode::caps_file_wanted()
{
int want = 0;
- for (map<int,int>::iterator p = open_by_mode.begin();
- p != open_by_mode.end();
- ++p)
- if (p->second)
- want |= ceph_caps_for_mode(p->first);
+ for (const auto &[mode, cnt] : open_by_mode)
+ if (cnt)
+ want |= ceph_caps_for_mode(mode);
return want;
}
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;
}
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;
if (is_dir()) {
f->dump_int("dir_hashed", (int)dir_hashed);
f->dump_int("dir_replicated", (int)dir_replicated);
+ if (dir_replicated) {
+ f->open_array_section("dirfrags");
+ for (const auto &frag : frag_repmap) {
+ f->open_object_section("frags");
+ CachedStackStringStream css;
+ *css << std::hex << frag.first.value() << "/" << std::dec << frag.first.bits();
+ f->dump_string("frag", css->strv());
+
+ f->open_array_section("repmap");
+ for (const auto &mds : frag.second) {
+ f->dump_int("mds", mds);
+ }
+ f->close_section();
+
+ f->close_section();
+ }
+ f->close_section();
+ }
}
f->open_array_section("caps");
for (const auto &pair : caps) {
f->open_object_section("cap");
- f->dump_int("mds", pair.first);
if (&pair.second == auth_cap)
f->dump_int("auth", 1);
pair.second.dump(f);
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()) {
f->open_array_section("parents");
- for (const auto &dn : dentries) {
+ for (const auto &&dn : dentries) {
f->open_object_section("dentry");
f->dump_stream("dir_ino") << dn->dir->parent_inode->ino;
f->dump_string("name", dn->name);
* allow it, with an unusual error to make it clear.
*/
if (!client->get_deleg_timeout())
- return -ETIME;
+ return -CEPHFS_ETIME;
// Just say no if we have any recalled delegs still outstanding
if (has_recalled_deleg()) {
lsubdout(client->cct, client, 10) << __func__ <<
": has_recalled_deleg" << dendl;
- return -EAGAIN;
+ return -CEPHFS_EAGAIN;
}
// check vs. currently open files on this inode
if (open_count_for_write()) {
lsubdout(client->cct, client, 10) << __func__ <<
": open for write" << dendl;
- return -EAGAIN;
+ return -CEPHFS_EAGAIN;
}
break;
case CEPH_DELEGATION_WR:
if (open_count() > 1) {
lsubdout(client->cct, client, 10) << __func__ << ": open" << dendl;
- return -EAGAIN;
+ return -CEPHFS_EAGAIN;
}
break;
default:
- return -EINVAL;
+ return -CEPHFS_EINVAL;
}
/*
if (!caps_issued_mask(need)) {
lsubdout(client->cct, client, 10) << __func__ << ": cap mismatch, have="
<< ccap_string(caps_issued()) << " need=" << ccap_string(need) << dendl;
- return -EAGAIN;
+ return -CEPHFS_EAGAIN;
}
for (list<Delegation>::iterator d = delegations.begin();
*/
void Inode::mark_caps_dirty(int caps)
{
+ /*
+ * If auth_cap is nullptr means the reonnecting is not finished or
+ * already rejected.
+ */
+ if (!auth_cap) {
+ ceph_assert(!dirty_caps);
+
+ lsubdout(client->cct, client, 1) << __func__ << " " << *this << " dirty caps '" << ccap_string(caps)
+ << "', but no auth cap." << dendl;
+ return;
+ }
+
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);
+ auth_cap->session->get_dirty_list().push_back(&dirty_cap_item);
+ client->cap_delay_requeue(this);
}
/**